From ddd9b1b21874fcbe1e802c54b3fcf5d45affb38b Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 16 Mar 2024 07:23:29 -0400 Subject: [PATCH] Extensive runtime refactor to reduce generated executable sizes --- BeefLibs/FMOD/src/FMod.bf | 15 +- BeefLibs/corlib/src/Attribute.bf | 6 + BeefLibs/corlib/src/Console.bf | 73 ++++- .../src/Diagnostics/Contracts/Contracts.bf | 9 +- BeefLibs/corlib/src/Diagnostics/Debug.bf | 16 +- BeefLibs/corlib/src/Double.bf | 4 + BeefLibs/corlib/src/Environment.bf | 19 +- BeefLibs/corlib/src/Float.bf | 4 + BeefLibs/corlib/src/GC.bf | 2 +- BeefLibs/corlib/src/Int.bf | 8 + BeefLibs/corlib/src/Int64.bf | 5 - BeefLibs/corlib/src/Internal.bf | 293 ++++++++++++++++-- BeefLibs/corlib/src/Math.bf | 17 +- BeefLibs/corlib/src/NumberFormatter.bf | 31 +- BeefLibs/corlib/src/Object.bf | 92 ++++-- BeefLibs/corlib/src/OperatingSystem.bf | 6 +- BeefLibs/corlib/src/Platform.bf | 275 +++++++++++++++- BeefLibs/corlib/src/Pointer.bf | 6 +- BeefLibs/corlib/src/Runtime.bf | 283 ++++++++++++++--- BeefLibs/corlib/src/Span.bf | 2 +- BeefLibs/corlib/src/String.bf | 33 +- BeefLibs/corlib/src/Test.bf | 2 +- BeefLibs/corlib/src/Text/Encoding.bf | 39 ++- BeefLibs/corlib/src/Threading/Thread.bf | 115 ++++--- BeefLibs/corlib/src/Type.bf | 29 +- BeefLibs/corlib/src/UInt.bf | 8 + BeefLibs/corlib/src/UInt64.bf | 2 - BeefRT/rt/BfObjects.h | 28 +- BeefRT/rt/Internal.cpp | 201 ++++++------ BeefRT/rt/Object.cpp | 4 +- BeefRT/rt/Thread.cpp | 81 ++--- BeefySysLib/platform/PlatformInterface.h | 2 + BeefySysLib/platform/win/CrashCatcher.cpp | 88 +++--- BeefySysLib/platform/win/Platform.cpp | 72 ++++- BeefySysLib/util/String.h | 115 ++++--- IDE/BeefProj.toml | 2 +- IDE/Tests/Tiny/BeefProj.toml | 8 + IDE/Tests/Tiny/BeefSpace.toml | 26 ++ IDE/Tests/Tiny/src/Program.bf | 13 + IDE/mintest/minlib/src/System/Attribute.bf | 22 +- IDE/mintest/minlib/src/System/Internal.bf | 9 +- IDE/mintest/minlib/src/System/Object.bf | 204 +++++++----- IDE/mintest/minlib/src/System/Type.bf | 6 +- IDE/mintest/src/main.bf | 8 +- IDE/src/BuildContext.bf | 12 +- IDE/src/BuildOptions.bf | 7 + IDE/src/Compiler/BfCompiler.bf | 7 +- IDE/src/Debugger/DebugManager.bf | 8 + IDE/src/IDEApp.bf | 7 + IDE/src/Workspace.bf | 27 +- IDE/src/ui/ModulePanel.bf | 14 + IDE/src/ui/WorkspaceProperties.bf | 2 + IDEHelper/COFF.cpp | 12 +- IDEHelper/Compiler/BfCompiler.cpp | 95 ++++-- IDEHelper/Compiler/BfCompiler.h | 2 + IDEHelper/Compiler/BfContext.cpp | 133 +++++--- IDEHelper/Compiler/BfContext.h | 1 + IDEHelper/Compiler/BfExprEvaluator.cpp | 38 ++- IDEHelper/Compiler/BfModule.cpp | 178 ++++++++--- IDEHelper/Compiler/BfModule.h | 14 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 39 ++- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 13 +- IDEHelper/Compiler/BfStmtEvaluator.cpp | 16 +- IDEHelper/Compiler/CeMachine.cpp | 4 +- IDEHelper/DbgModule.cpp | 12 +- IDEHelper/DbgModule.h | 5 +- IDEHelper/DebugManager.cpp | 7 + IDEHelper/Debugger.h | 1 + IDEHelper/HotScanner.cpp | 70 ++++- IDEHelper/HotScanner.h | 1 + IDEHelper/Tests/BeefSpace.toml | 3 + IDEHelper/WinDebugger.cpp | 204 ++++++++++++ IDEHelper/WinDebugger.h | 1 + bin/test_build.bat | 15 +- 74 files changed, 2514 insertions(+), 717 deletions(-) create mode 100644 IDE/Tests/Tiny/BeefProj.toml create mode 100644 IDE/Tests/Tiny/BeefSpace.toml create mode 100644 IDE/Tests/Tiny/src/Program.bf diff --git a/BeefLibs/FMOD/src/FMod.bf b/BeefLibs/FMOD/src/FMod.bf index 90f8381e..7ebd85bc 100644 --- a/BeefLibs/FMOD/src/FMod.bf +++ b/BeefLibs/FMOD/src/FMod.bf @@ -15,12 +15,8 @@ namespace FMOD */ public class VERSION { - public const int32 number = 0x00010803; -#if BF_64_BIT - public const String dll = "fmod64.dll"; -#else - public const String dll = "fmod.dll"; -#endif + public const int32 number = 0x00020220; + public const String dll = "fmod.dll"; } public class CONSTANTS @@ -1385,7 +1381,7 @@ namespace FMOD public int fileuserdata; /* [w] Optional. Specify 0 to ignore. User data to be passed into the file callbacks. */ public int32 filebuffersize; /* [w] Optional. Specify 0 to ignore. Buffer size for reading the file, -1 to disable buffering, or 0 for system default. */ public CHANNELORDER channelorder; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_CHANNELORDER for more. */ - public CHANNELMASK channelmask; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_CHANNELMASK for more. */ + //public CHANNELMASK channelmask; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_CHANNELMASK for more. */ public int initialsoundgroup; /* [w] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ public uint32 initialseekposition; /* [w] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ public TIMEUNIT initialseekpostype; /* [w] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ @@ -1587,7 +1583,7 @@ namespace FMOD RESULT result = RESULT.OK; int rawPtr = 0; - result = FMOD_System_Create(out rawPtr); + result = FMOD_System_Create(out rawPtr, VERSION.number); if (result != RESULT.OK) { return result; @@ -1602,7 +1598,7 @@ namespace FMOD #region importfunctions [Import(VERSION.dll), CLink, CallingConvention(.Stdcall)] - private static extern RESULT FMOD_System_Create (out int system); + private static extern RESULT FMOD_System_Create (out int system, uint headerversion); #endregion } @@ -2008,6 +2004,7 @@ namespace FMOD stringData = name.CStr(); exinfo.cbsize = (int32)sizeof(CREATESOUNDEXINFO); + //int offset = offsetof(CREATESOUNDEXINFO, channelmask); int soundraw; RESULT result = FMOD_System_CreateSound(rawPtr, stringData, mode, ref exinfo, out soundraw); diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index 9f33dd5f..bc6b8a09 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -172,6 +172,12 @@ namespace System } + [AttributeUsage(.MemberAccess)] + public struct NoStaticCtorAttribute : Attribute + { + + } + [AttributeUsage(.Block)] public struct ConstSkipAttribute : Attribute diff --git a/BeefLibs/corlib/src/Console.bf b/BeefLibs/corlib/src/Console.bf index ceb21f0d..3f40cfc6 100644 --- a/BeefLibs/corlib/src/Console.bf +++ b/BeefLibs/corlib/src/Console.bf @@ -13,8 +13,38 @@ namespace System CtrlBreak } - static Encoding InputEncoding = Encoding.ASCII; - static Encoding OutputEncoding = Encoding.ASCII; + public struct CancelInfo + { + public static Event sOnCancel ~ _.Dispose(); + public static bool sCancelEventRegistered; + } + + static Encoding sInputEncoding; + static Encoding sOutputEncoding; + + static Encoding InputEncoding + { + get + { + return sInputEncoding ?? Encoding.ASCII; + } + set + { + sInputEncoding = value; + } + } + static Encoding OutputEncoding + { + get + { + return sOutputEncoding ?? Encoding.ASCII; + } + set + { + SetupOutStringEx(); + sOutputEncoding = value; + } + } static ConsoleColor sForegroundColor = .White; static ConsoleColor sBackgroundColor = .Black; @@ -22,9 +52,6 @@ namespace System static readonly ConsoleColor sOriginalForegroundColor = sForegroundColor; static readonly ConsoleColor sOriginalBackgroundColor = sBackgroundColor; - static Event sOnCancel ~ _.Dispose(); - static bool sCancelEventRegistered; - public static ConsoleColor ForegroundColor { get { return sForegroundColor; } @@ -56,18 +83,39 @@ namespace System { } + static void SetupOutStringEx() + { + OutString = => OutString_Ex; + } + + static function void(StringView str) OutString = => OutString_Simple; + + [CLink, CallingConvention(.Cdecl)] + static extern void putchar(char8 c); + + static void OutString_Simple(StringView str) + { + for (var c in str.RawChars) + putchar(c); + } + + static void OutString_Ex(StringView str) + { + Out.Write(str).IgnoreError(); + } + public static ref Event OnCancel { get { - if (!sCancelEventRegistered) + if (!CancelInfo.sCancelEventRegistered) { - sCancelEventRegistered = true; + CancelInfo.sCancelEventRegistered = true; #if BF_PLATFORM_WINDOWS SetConsoleCtrlHandler(=> ConsoleCtrlHandler, true); #endif } - return ref sOnCancel; + return ref CancelInfo.sOnCancel; } } @@ -77,7 +125,7 @@ namespace System { bool terminate = true; if ((ctrlType == 0) || (ctrlType == 1)) - sOnCancel((.)ctrlType, ref terminate); + CancelInfo.sOnCancel((.)ctrlType, ref terminate); return terminate ? false : true; } @@ -286,7 +334,7 @@ namespace System public static void Write(StringView line) { - Out.Write(line).IgnoreError(); + OutString(line); } public static void Write(StringView fmt, params Object[] args) @@ -308,12 +356,13 @@ namespace System public static void WriteLine() { - Out.Write("\n").IgnoreError(); + OutString("\n"); } public static void WriteLine(StringView line) { - Out.WriteLine(line).IgnoreError(); + OutString(line); + OutString("\n"); } public static void WriteLine(StringView fmt, params Object[] args) diff --git a/BeefLibs/corlib/src/Diagnostics/Contracts/Contracts.bf b/BeefLibs/corlib/src/Diagnostics/Contracts/Contracts.bf index e5f7d80c..c9279915 100644 --- a/BeefLibs/corlib/src/Diagnostics/Contracts/Contracts.bf +++ b/BeefLibs/corlib/src/Diagnostics/Contracts/Contracts.bf @@ -13,8 +13,15 @@ namespace System.Diagnostics.Contracts Assert, Assume, } - + +#if !BF_RUNTIME_DISABLE static extern void ReportFailure(ContractFailureKind failureKind, char8* userMessage, int32 userMessageLen, char8* conditionText, int32 conditionTextLen); +#else + static void ReportFailure(ContractFailureKind failureKind, char8* userMessage, int32 userMessageLen, char8* conditionText, int32 conditionTextLen) + { + Internal.FatalError("Contract.ReportFailure"); + } +#endif /// /// This method is used internally to trigger a failure indicating to the "programmer" that he is using the interface incorrectly. diff --git a/BeefLibs/corlib/src/Diagnostics/Debug.bf b/BeefLibs/corlib/src/Diagnostics/Debug.bf index e8b9b420..6ed87ebb 100644 --- a/BeefLibs/corlib/src/Diagnostics/Debug.bf +++ b/BeefLibs/corlib/src/Diagnostics/Debug.bf @@ -9,10 +9,16 @@ namespace System.Diagnostics { if (!condition) { - if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Debug, error, filePath, line)) == .Ignore) + if ((Runtime.CheckAssertError != null) && (Runtime.CheckAssertError(.Debug, error, filePath, line) == .Ignore)) return; - String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath); +#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 } } @@ -21,7 +27,9 @@ namespace System.Diagnostics #endif 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); + String failStr = scope .()..Append(msg, " at line "); + line.ToString(failStr); + failStr.Append(" in ", filePath); Internal.FatalError(failStr, 1); } @@ -87,7 +95,7 @@ namespace System.Diagnostics } static bool gIsDebuggerPresent = IsDebuggerPresent; - [LinkName("IsDebuggerPresent"), CallingConvention(.Stdcall)] + [LinkName("IsDebuggerPresent"), CallingConvention(.Stdcall), Import("kernel32.lib")] static extern int32 Internal_IsDebuggerPresent(); public static bool IsDebuggerPresent diff --git a/BeefLibs/corlib/src/Double.bf b/BeefLibs/corlib/src/Double.bf index 9e4d11bf..f8046502 100644 --- a/BeefLibs/corlib/src/Double.bf +++ b/BeefLibs/corlib/src/Double.bf @@ -199,7 +199,11 @@ namespace System [CallingConvention(.Stdcall), CLink] static extern int32 ftoa(float val, char8* str); +#if !BF_RUNTIME_DISABLE static extern int32 ToString(double val, char8* str, bool roundTrip); +#else + static int32 ToString(double val, char8* str, bool roundTrip) => Runtime.NotImplemented(); +#endif public override void ToString(String strBuffer) { diff --git a/BeefLibs/corlib/src/Environment.bf b/BeefLibs/corlib/src/Environment.bf index d65e2bb5..92c73e69 100644 --- a/BeefLibs/corlib/src/Environment.bf +++ b/BeefLibs/corlib/src/Environment.bf @@ -1,6 +1,7 @@ using System.IO; using System.Collections; using System.Text; +using System.Threading; namespace System { @@ -12,7 +13,23 @@ namespace System public static readonly String NewLine = "\n"; #endif // BF_PLATFORM_WINDOWS - public static OperatingSystem OSVersion = new OperatingSystem() ~ delete _; + + static OperatingSystem sOSVersion ~ delete _; + public static OperatingSystem OSVersion + { + get + { + var osVersion = new OperatingSystem(); + let prevValue = Interlocked.CompareExchange(ref sOSVersion, null, osVersion); + if (prevValue != null) + { + // This was already set - race condition + delete osVersion; + return prevValue; + } + return osVersion; + } + } public static void* ModuleHandle => Internal.[Friend]sModuleHandle; diff --git a/BeefLibs/corlib/src/Float.bf b/BeefLibs/corlib/src/Float.bf index be3e3ba1..e26328b6 100644 --- a/BeefLibs/corlib/src/Float.bf +++ b/BeefLibs/corlib/src/Float.bf @@ -147,7 +147,11 @@ namespace System [CallingConvention(.Stdcall), CLink] static extern int32 ftoa(float val, char8* str); +#if !BF_RUNTIME_DISABLE static extern int32 ToString(float val, char8* str, bool roundTrip); +#else + static int32 ToString(float val, char8* str, bool roundTrip) => Runtime.FatalError(); +#endif public override void ToString(String strBuffer) { diff --git a/BeefLibs/corlib/src/GC.bf b/BeefLibs/corlib/src/GC.bf index 04153c0c..6d8bed7e 100644 --- a/BeefLibs/corlib/src/GC.bf +++ b/BeefLibs/corlib/src/GC.bf @@ -91,7 +91,7 @@ namespace System #endif } -#if BF_ENABLE_REALTIME_LEAK_CHECK || BF_DEBUG_ALLOC +#if (BF_ENABLE_REALTIME_LEAK_CHECK || BF_DEBUG_ALLOC) && !BF_RUNTIME_DISABLE [CallingConvention(.Cdecl)] public extern static void Report(); [CallingConvention(.Cdecl)] diff --git a/BeefLibs/corlib/src/Int.bf b/BeefLibs/corlib/src/Int.bf index 3a72fad2..8954acba 100644 --- a/BeefLibs/corlib/src/Int.bf +++ b/BeefLibs/corlib/src/Int.bf @@ -13,6 +13,14 @@ namespace System case InvalidChar(int partialResult); } + public struct Simple : int + { + public override void ToString(String strBuffer) + { + ((int)this).ToString(strBuffer); + } + } + public const int MaxValue = (sizeof(int) == 8) ? 0x7FFFFFFFFFFFFFFFL : 0x7FFFFFFF; public const int MinValue = (sizeof(int) == 8) ? -0x8000000000000000L : -0x80000000; diff --git a/BeefLibs/corlib/src/Int64.bf b/BeefLibs/corlib/src/Int64.bf index e361cf19..71436789 100644 --- a/BeefLibs/corlib/src/Int64.bf +++ b/BeefLibs/corlib/src/Int64.bf @@ -63,11 +63,6 @@ namespace System } } - //static char8[] sHexUpperChars = new char8[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'} ~ delete _; - //static char8[] sHexLowerChars = new char8[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} ~ delete _; - - static String sHexUpperChars = "0123456789ABCDEF"; - static String sHexLowerChars = "0123456789abcdef"; public void ToString(String outString, String format, IFormatProvider formatProvider) { if(format == null || format.IsEmpty) diff --git a/BeefLibs/corlib/src/Internal.bf b/BeefLibs/corlib/src/Internal.bf index 0ecbd02a..22854d23 100644 --- a/BeefLibs/corlib/src/Internal.bf +++ b/BeefLibs/corlib/src/Internal.bf @@ -81,12 +81,6 @@ namespace System public static extern Object UnsafeCastToObject(void* ptr); [Intrinsic("cast")] public static extern void* UnsafeCastToPtr(Object obj); - [CallingConvention(.Cdecl), NoReturn] - public static extern void ThrowIndexOutOfRange(int stackOffset = 0); - [CallingConvention(.Cdecl), NoReturn] - public static extern void ThrowObjectNotInitialized(int stackOffset = 0); - [CallingConvention(.Cdecl), NoReturn] - public static extern void FatalError(String error, int stackOffset = 0); [Intrinsic("memcpy")] public static extern void MemCpy(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false); [Intrinsic("memmove")] @@ -103,6 +97,32 @@ namespace System public static extern void StdFree(void* ptr); [Intrinsic("returnaddress")] public static extern void* GetReturnAddress(int32 level = 0); + + [CallingConvention(.Cdecl)] + static extern void Test_Init(char8* testData); + [CallingConvention(.Cdecl)] + static extern void Test_Error(char8* error); + [CallingConvention(.Cdecl)] + static extern void Test_Write(char8* str); + [CallingConvention(.Cdecl)] + static extern int32 Test_Query(); + [CallingConvention(.Cdecl)] + static extern void Test_Finish(); + + static void* sModuleHandle; + [AlwaysInclude] + static void SetModuleHandle(void* handle) + { + sModuleHandle = handle; + } + +#if !BF_RUNTIME_DISABLE + [CallingConvention(.Cdecl), NoReturn] + public static extern void ThrowIndexOutOfRange(int stackOffset = 0); + [CallingConvention(.Cdecl), NoReturn] + public static extern void ThrowObjectNotInitialized(int stackOffset = 0); + [CallingConvention(.Cdecl), NoReturn] + public static extern void FatalError(String error, int stackOffset = 0); [CallingConvention(.Cdecl)] public static extern void* VirtualAlloc(int size, bool canExecute, bool canWrite); [CallingConvention(.Cdecl)] @@ -160,25 +180,236 @@ namespace System [CallingConvention(.Cdecl)] public static extern void Dbg_RawFree(void* ptr); - [CallingConvention(.Cdecl), AlwaysInclude] - static extern void Shutdown(); [CallingConvention(.Cdecl)] - static extern void Test_Init(char8* testData); - [CallingConvention(.Cdecl)] - static extern void Test_Error(char8* error); - [CallingConvention(.Cdecl)] - static extern void Test_Write(char8* str); - [CallingConvention(.Cdecl)] - static extern int32 Test_Query(); - [CallingConvention(.Cdecl)] - static extern void Test_Finish(); + static extern void Shutdown_Internal(); - static void* sModuleHandle; - [AlwaysInclude] - static void SetModuleHandle(void* handle) + [CallingConvention(.Cdecl), AlwaysInclude] + static void Shutdown() { - sModuleHandle = handle; + Shutdown_Internal(); + Runtime.Shutdown(); } + #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() + { + char8* ptr = null; + *ptr = 'A'; + } + + [AlwaysInclude, NoReturn] + public static void ThrowIndexOutOfRange(int stackOffset = 0) + { + Crash(); + } + + [AlwaysInclude, NoReturn] + public static void ThrowObjectNotInitialized(int stackOffset = 0) + { + Crash(); + } + + [AlwaysInclude, NoReturn] + public static void FatalError(String error, int stackOffset = 0) + { + Crash(); + } + + [AlwaysInclude] + public static void* VirtualAlloc(int size, bool canExecute, bool canWrite) + { + return null; + } + + public static int32 CStrLen(char8* charPtr) + { + int32 len = 0; + while (charPtr[len] != 0) + len++; + return len; + } + + public static int64 GetTickCountMicro() + { + return 0; + } + + + [AlwaysInclude] + public static void BfDelegateTargetCheck(void* target) + { + + } + + [AlwaysInclude] + public static void* LoadSharedLibrary(char8* filePath) + { + return null; + } + + [AlwaysInclude] + public static void LoadSharedLibraryInto(char8* filePath, void** libDest) + { + + } + + [AlwaysInclude] + public static void* GetSharedProcAddress(void* libHandle, char8* procName) + { + return null; + } + + [AlwaysInclude] + public static void GetSharedProcAddressInto(void* libHandle, char8* procName, void** procDest) + { + + } + + [AlwaysInclude] + public static char8* GetCommandLineArgs() + { + return ""; + } + + public static void ProfilerCmd(char8* str) + { + + } + + public static void ReportMemory() + { + + } + + public static void ObjectDynCheck(Object obj, int32 typeId, bool allowNull) + { + + } + + public static void ObjectDynCheckFailed(Object obj, int32 typeId) + { + + } + + [DisableChecks, DisableObjectAccessChecks] + public static void Dbg_ObjectCreated(Object obj, int size, ClassVData* classVData) + { + } + + [DisableChecks, DisableObjectAccessChecks] + public static void Dbg_ObjectCreatedEx(Object obj, int size, ClassVData* classVData) + { + + } + + [DisableChecks, DisableObjectAccessChecks] + public static void Dbg_ObjectAllocated(Object obj, int size, ClassVData* classVData) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + obj.[Friend]mClassVData = (.)(void*)classVData; + obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0); +#else + obj.[Friend]mClassVData = classVData; +#endif + } + + [DisableChecks, DisableObjectAccessChecks] + public static void Dbg_ObjectAllocatedEx(Object obj, int size, ClassVData* classVData) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + obj.[Friend]mClassVData = (.)(void*)classVData; + obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0); +#else + obj.[Friend]mClassVData = classVData; +#endif + } + + public static int Dbg_PrepareStackTrace(int baseAllocSize, int maxStackTraceDepth) + { + return 0; + } + + [DisableChecks, DisableObjectAccessChecks] + public static void Dbg_ObjectStackInit(Object obj, ClassVData* classVData) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + obj.[Friend]mClassVData = (.)(void*)classVData; + obj.[Friend]mClassVData |= (.)BfObjectFlags.StackAlloc; + obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0); +#else + obj.[Friend]mClassVData = classVData; +#endif + } + + public static Object Dbg_ObjectAlloc(TypeInstance typeInst, int size) + { + return null; + } + + public static Object Dbg_ObjectAlloc(ClassVData* classVData, int size, int align, int maxStackTraceDepth) + { + return null; + } + + public static void Dbg_ObjectPreDelete(Object obj) + { + + } + + public static void Dbg_ObjectPreCustomDelete(Object obj) + { + + } + + public static void Dbg_MarkObjectDeleted(Object obj) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + obj.[Friend]mClassVData |= (.)BfObjectFlags.Deleted; +#endif + } + + public static void* Dbg_RawAlloc(int size) + { + return null; + } + + public static void* Dbg_RawObjectAlloc(int size) + { + return null; + } + + public static void* Dbg_RawAlloc(int size, DbgRawAllocData* rawAllocData) + { + return null; + } + + public static void Dbg_RawFree(void* ptr) + { + + } + + [AlwaysInclude] + static void Shutdown() + { + + } + #endif + [AlwaysInclude] static void AddRtFlags(int32 flags) { @@ -209,15 +440,15 @@ namespace System } [Error("Cannot be called directly"), SkipCall] - static void SetDeleted1(void* dest); + static void SetDeleted1(void* dest); [Error("Cannot be called directly"), SkipCall] - static void SetDeleted4(void* dest); + static void SetDeleted4(void* dest); [Error("Cannot be called directly"), SkipCall] - static void SetDeleted8(void* dest); + static void SetDeleted8(void* dest); [Error("Cannot be called directly"), SkipCall] - static void SetDeleted16(void* dest); + static void SetDeleted16(void* dest); [Error("Cannot be called directly"), SkipCall] - static extern void SetDeletedX(void* dest, int size); + static extern void SetDeletedX(void* dest, int size); [Error("Cannot be called directly"), SkipCall] static extern void SetDeleted(void* dest, int size, int32 align); [Error("Cannot be called directly"), SkipCall] @@ -254,9 +485,9 @@ namespace System } } - [AlwaysInclude] public static String[] CreateParamsArray() { +#if !BF_RUNTIME_DISABLE char8* cmdLine = GetCommandLineArgs(); //Windows.MessageBoxA(default, scope String()..AppendF("CmdLine: {0}", StringView(cmdLine)), "HI", 0); @@ -336,7 +567,7 @@ namespace System if (firstCharIdx == -1) firstCharIdx = i; if (c == '^') - { + { i++; } if (c == '"') @@ -357,9 +588,11 @@ namespace System } return strVals; +#else + return new String[0]; +#endif } - [AlwaysInclude] public static void DeleteStringArray(String[] arr) { for (var str in arr) @@ -367,8 +600,10 @@ namespace System delete arr; } +#if !BF_RUNTIME_DISABLE extern static this(); extern static ~this(); +#endif } struct CRTAlloc diff --git a/BeefLibs/corlib/src/Math.bf b/BeefLibs/corlib/src/Math.bf index 260916fd..8fd4074f 100644 --- a/BeefLibs/corlib/src/Math.bf +++ b/BeefLibs/corlib/src/Math.bf @@ -223,7 +223,8 @@ namespace System modf(d, out intPart); return intPart; } - + +#if !BF_RUNTIME_DISABLE public static extern float Sqrt(float f); public static extern double Sqrt(double d); public static extern float Cbrt(float f); @@ -236,6 +237,20 @@ namespace System public static extern double Exp(double d); public static extern float Pow(float x, float y); public static extern double Pow(double x, double y); +#else + public static float Sqrt(float f) => Runtime.NotImplemented(); + public static double Sqrt(double d) => Runtime.NotImplemented(); + public static float Cbrt(float f) => Runtime.NotImplemented(); + public static double Cbrt(double d) => Runtime.NotImplemented(); + public static float Log(float f) => Runtime.NotImplemented(); + public static double Log(double d) => Runtime.NotImplemented(); + public static float Log10(float f) => Runtime.NotImplemented(); + public static double Log10(double d) => Runtime.NotImplemented(); + public static float Exp(float f) => Runtime.NotImplemented(); + public static double Exp(double d) => Runtime.NotImplemented(); + public static float Pow(float x, float y) => Runtime.NotImplemented(); + public static double Pow(double x, double y) => Runtime.NotImplemented(); +#endif public static float IEEERemainder(float x, float y) { diff --git a/BeefLibs/corlib/src/NumberFormatter.bf b/BeefLibs/corlib/src/NumberFormatter.bf index 4f14c6db..332a958c 100644 --- a/BeefLibs/corlib/src/NumberFormatter.bf +++ b/BeefLibs/corlib/src/NumberFormatter.bf @@ -1130,12 +1130,14 @@ namespace System // Hexadecimal digits representation. private static uint32 FastToDecHex (int32 val) { + var decHexDigits = DecHexDigits; + if (val < 100) - return (uint32)DecHexDigits [val]; + return (uint32)decHexDigits[val]; // Uses 2^19 (524288) to compute val / 100 for val < 10000. int32 v = (val * 5243) >> 19; - return (uint32)((DecHexDigits [v] << 8) | DecHexDigits [val - v * 100]); + return (uint32)((decHexDigits[v] << 8) | decHexDigits[val - v * 100]); } // Helper to translate an int in the range 0 .. 99999999 to its @@ -1741,6 +1743,31 @@ namespace System inst.IntegerToString(format, fp, outString); } + public static void AddrToString (uint value, String outString) + { + const int bufLen = 18; + char8* strChars = scope:: char8[bufLen]* (?); + int32 curLen = 0; + uint64 valLeft = (.)value; + while (valLeft > 0) + { + if (curLen == 8) + strChars[bufLen - curLen++ - 1] = '\''; + strChars[bufLen - curLen++ - 1] = DigitUpperTable[(int)(valLeft & 0xF)]; + valLeft >>= 4; + } + + while (curLen < 10) + { + if (curLen == 8) + strChars[bufLen - curLen++ - 1] = '\''; + strChars[bufLen - curLen++ - 1] = '0'; + } + + char8* char8Ptr = &strChars[bufLen - curLen]; + outString.Append(char8Ptr, curLen); + } + public static void NumberToString (StringView format, int32 value, IFormatProvider fp, String outString) { NumberFormatter inst = GetInstance!(fp); diff --git a/BeefLibs/corlib/src/Object.bf b/BeefLibs/corlib/src/Object.bf index 6ea3acfa..6dc25031 100644 --- a/BeefLibs/corlib/src/Object.bf +++ b/BeefLibs/corlib/src/Object.bf @@ -10,10 +10,11 @@ namespace System #if BF_ENABLE_OBJECT_DEBUG_FLAGS int mClassVData; int mDbgAllocInfo; -#else +#else ClassVData* mClassVData; #endif - + + [AlwaysInclude] public virtual ~this() { #if BF_ENABLE_OBJECT_DEBUG_FLAGS @@ -47,42 +48,79 @@ namespace System if (Compiler.IsComptime) return Comptime_GetType(); - Type type; + ClassVData* classVData; #if BF_ENABLE_OBJECT_DEBUG_FLAGS - ClassVData* maskedVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); - type = maskedVData.mType; + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); #else - type = mClassVData.mType; + classVData = mClassVData; +#endif + +#if BF_32_BIT + Type type = Type.[Friend]GetType_(classVData.mType2); +#else + Type type = Type.[Friend]GetType_((.)(classVData.mType >> 32)); #endif - if ((type.[Friend]mTypeFlags & TypeFlags.Boxed) != 0) - { - //int32 underlyingType = (int32)((TypeInstance)type).mUnderlyingType; - type = Type.[Friend]GetType(((TypeInstance)type).[Friend]mUnderlyingType); - } return type; } + TypeId GetTypeId() + { + ClassVData* classVData; +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + return (.)classVData.mType2; +#else + return (.)(classVData.mType >> 32); +#endif + } + [NoShow] Type RawGetType() { if (Compiler.IsComptime) return Comptime_GetType(); - Type type; + ClassVData* classVData; #if BF_ENABLE_OBJECT_DEBUG_FLAGS - ClassVData* maskedVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); - type = maskedVData.mType; -#else - type = mClassVData.mType; -#endif - return type; + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + Type type = Type.[Friend]GetType_(classVData.mType); +#else + Type type = Type.[Friend]GetType_((.)(classVData.mType & 0xFFFFFFFF)); +#endif + return type; } + TypeId RawGetTypeId() + { + ClassVData* classVData; +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + return (.)classVData.mType; +#else + return (.)(classVData.mType & 0xFFFFFFFF); +#endif + } + #if BF_DYNAMIC_CAST_CHECK || BF_ENABLE_REALTIME_LEAK_CHECK [NoShow] public virtual Object DynamicCastToTypeId(int32 typeId) { - if (typeId == (int32)RawGetType().[Friend]mTypeId) + if (typeId == (.)RawGetTypeId()) return this; return null; } @@ -98,9 +136,13 @@ namespace System { return (int)Internal.UnsafeCastToPtr(this); } - + public virtual void ToString(String strBuffer) { +#if BF_REFLECT_MINIMAL + strBuffer.AppendF($"Type#{(Int.Simple)GetTypeId()}@0x"); + NumberFormatter.AddrToString((uint)Internal.UnsafeCastToPtr(this), strBuffer); +#else let t = RawGetType(); if (t.IsBoxedStructPtr) { @@ -108,13 +150,15 @@ namespace System let innerPtr = *(void**)((uint8*)Internal.UnsafeCastToPtr(this) + ti.[Friend]mMemberDataOffset); strBuffer.Append("("); ti.UnderlyingType.GetFullName(strBuffer); - strBuffer.AppendF("*)0x{0:A}", (uint)(void*)innerPtr); + //strBuffer.AppendF("*)0x{0:A}", (UInt.Simple)(uint)(void*)innerPtr); + strBuffer.Append("*)0x"); + NumberFormatter.AddrToString((uint)(void*)innerPtr, strBuffer); return; } t.GetFullName(strBuffer); strBuffer.Append("@0x"); - - ((int)Internal.UnsafeCastToPtr(this)).ToString(strBuffer, "A", null); + NumberFormatter.AddrToString((uint)Internal.UnsafeCastToPtr(this), strBuffer); +#endif } private static void ToString(Object obj, String strBuffer) @@ -124,7 +168,7 @@ namespace System else obj.ToString(strBuffer); } - + [SkipCall, NoShow] protected virtual void GCMarkMembers() { diff --git a/BeefLibs/corlib/src/OperatingSystem.bf b/BeefLibs/corlib/src/OperatingSystem.bf index 117c6819..2fc3f988 100644 --- a/BeefLibs/corlib/src/OperatingSystem.bf +++ b/BeefLibs/corlib/src/OperatingSystem.bf @@ -78,7 +78,7 @@ namespace System public uint32 dwFileDateLS; // e.g. 0 } - [CLink, CallingConvention(.Stdcall)] + [Import("kernel32.lib"), CLink, CallingConvention(.Stdcall)] extern static bool GetVersionExA(OSVersionInfoExA* lpVersionInformation); [CLink, CallingConvention(.Stdcall)] @@ -274,9 +274,9 @@ namespace System String arch = Arch32; #endif if (Version.Revision == 0) - outVar.AppendF("{} (Version {}.{}, Build {}, {})", Name, Version.Major, Version.Minor, Version.Build, arch); + outVar.AppendF("{} (Version {}.{}, Build {}, {})", Name, (UInt.Simple)Version.Major, (UInt.Simple)Version.Minor, (UInt.Simple)Version.Build, arch); else - outVar.AppendF("{} Service Pack {} (Version {}.{}, Build {}, {})", Name, Version.Revision, Version.Major, Version.Minor, Version.Build, arch); + outVar.AppendF("{} Service Pack {} (Version {}.{}, Build {}, {})", Name, (UInt.Simple)Version.Revision, (UInt.Simple)Version.Major, (UInt.Simple)Version.Minor, (UInt.Simple)Version.Build, arch); #elif BF_PLATFORM_LINUX outVar.AppendF("{} {} (Version {}.{}.{})", PrettyName, Name, Version.Major, Version.Minor, Version.Revision); #else // MACOS and ANDROID diff --git a/BeefLibs/corlib/src/Platform.bf b/BeefLibs/corlib/src/Platform.bf index 7fc94710..d4256a22 100644 --- a/BeefLibs/corlib/src/Platform.bf +++ b/BeefLibs/corlib/src/Platform.bf @@ -34,15 +34,29 @@ namespace System NotEmpty }; - public struct BfpCritSect {} public struct BfpSpawn {} public struct BfpFile {} public struct BfpFindFileData {} public struct BfpDynLib {} - public struct BfpEvent {}; + public struct BfpFileWatcher {} public struct BfpProcess {} public struct BfpTLS; +#if !BF_RUNTIME_DISABLE + public struct BfpCritSect {} + public struct BfpEvent {}; +#else + public struct BfpCritSect + { + public int mEmpty; + } + + public struct BfpEvent + { + public bool mSet; + public bool mAuto; + }; +#endif public enum BfpSystemResult : int32 { @@ -51,6 +65,7 @@ namespace System TempFileError = (int)Result.TempFileError } +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern uint32 BfpSystem_TickCount(); [CallingConvention(.Stdcall), CLink] @@ -107,6 +122,62 @@ namespace System public static extern void BfpTLS_SetValue(BfpTLS* tls, void* value); [CallingConvention(.Stdcall), CLink] public static extern void* BfpTLS_GetValue(BfpTLS* tls); +#else + + public static uint32 BfpSystem_TickCount() => Runtime.NotImplemented(); + + public static uint32 BfpSystem_SetCrashRelaunchCmd(char8* cmd) => Runtime.NotImplemented(); + + public static BfpTimeStamp BfpSystem_GetTimeStamp() => Runtime.NotImplemented(); + + public static uint8 BfpSystem_InterlockedExchange8(uint8* ptr, uint8 val) => Runtime.NotImplemented(); + + public static uint16 BfpSystem_InterlockedExchange16(uint16* ptr, uint16 val) => Runtime.NotImplemented(); + + public static uint32 BfpSystem_InterlockedExchange32(uint32* ptr, uint32 val) => Runtime.NotImplemented(); + + public static uint64 BfpSystem_InterlockedExchange64(uint64* ptr, uint64 val) => Runtime.NotImplemented(); + + public static uint8 BfpSystem_InterlockedExchangeAdd8(uint8* ptr, uint8 val) => Runtime.NotImplemented(); + + public static uint16 BfpSystem_InterlockedExchangeAdd16(uint16* ptr, uint16 val) => Runtime.NotImplemented(); /// Returns the initial value in 'ptr' + + public static uint32 BfpSystem_InterlockedExchangeAdd32(uint32* ptr, uint32 val) => Runtime.NotImplemented(); /// Returns the initial value in 'ptr' + + public static uint64 BfpSystem_InterlockedExchangeAdd64(uint64* ptr, uint64 val) => Runtime.NotImplemented(); + + public static uint8 BfpSystem_InterlockedCompareExchange8(uint8* ptr, uint8 oldVal, uint8 newVal) => Runtime.NotImplemented(); + + public static uint16 BfpSystem_InterlockedCompareExchange16(uint16* ptr, uint16 oldVal, uint16 newVal) => Runtime.NotImplemented(); + + public static uint32 BfpSystem_InterlockedCompareExchange32(uint32* ptr, uint32 oldVal, uint32 newVal) => Runtime.NotImplemented(); + + public static uint64 BfpSystem_InterlockedCompareExchange64(uint64* ptr, uint64 oldVal, uint64 newVal) => Runtime.NotImplemented(); + + public static void BfpSystem_GetExecutablePath(char8* outStr, int32* inOutStrSize, BfpSystemResult* outResult) => Runtime.NotImplemented(); + + public static void BfpSystem_GetEnvironmentStrings(char8* outStr, int32* inOutStrSize, BfpSystemResult* outResult) => Runtime.NotImplemented(); + + public static int32 BfpSystem_GetNumLogicalCPUs(BfpSystemResult* outResult) => Runtime.NotImplemented(); + + public static int64 BfpSystem_GetCPUTick() => Runtime.NotImplemented(); + + public static int64 BfpSystem_GetCPUTickFreq() => Runtime.NotImplemented(); + + public static void BfpSystem_CreateGUID(Guid* outGuid) => Runtime.NotImplemented(); + + public static void BfpSystem_GetComputerName(char8* outStr, int32* inOutStrSize, BfpSystemResult* outResult) => Runtime.NotImplemented(); + + public static int BfpThread_GetCurrentId() => Runtime.NotImplemented(); + + public static BfpTLS* BfpTLS_Create(function [CallingConvention(.Stdcall)] void(void*) exitProc) => Runtime.NotImplemented(); + + public static void BfpTLS_Release(BfpTLS* tls) => Runtime.NotImplemented(); + + public static void BfpTLS_SetValue(BfpTLS* tls, void* value) => Runtime.NotImplemented(); + + public static void* BfpTLS_GetValue(BfpTLS* tls) => Runtime.NotImplemented(); +#endif public enum BfpFileWatcherFlags : int32 { @@ -125,10 +196,16 @@ namespace System public function void BfpDirectoryChangeFunc(BfpFileWatcher* watcher, void* userData, BfpFileChangeKind changeKind, char8* directory, char8* fileName, char8* oldName); +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpFileWatcher* BfpFileWatcher_WatchDirectory(char8* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern void BfpFileWatcher_Release(BfpFileWatcher* fileWatcher); +#else + public static BfpFileWatcher* BfpFileWatcher_WatchDirectory(char8* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFileWatcher_Release(BfpFileWatcher* fileWatcher) => Runtime.NotImplemented(); +#endif public enum BfpProcessResult : int32 { @@ -136,6 +213,7 @@ namespace System InsufficientBuffer = (int)Result.InsufficientBuffer } +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern bool BfpProcess_IsRemoteMachine(char8* machineName); [CallingConvention(.Stdcall), CLink] @@ -150,6 +228,22 @@ namespace System public static extern void BfpProcess_GetProcessName(BfpProcess* process, char8* outName, int32* inOutNameSize, BfpProcessResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern int32 BfpProcess_GetProcessId(BfpProcess* process); +#else + + public static bool BfpProcess_IsRemoteMachine(char8* machineName) => Runtime.NotImplemented(); + + public static BfpProcess* BfpProcess_GetById(char8* machineName, int32 processId, BfpProcessResult* outResult) => Runtime.NotImplemented(); + + public static void BfpProcess_Enumerate(char8* machineName, BfpProcess** outProcesses, int32* inOutProcessesSize, BfpProcessResult* outResult) => Runtime.NotImplemented(); + + public static void BfpProcess_Release(BfpProcess* process) => Runtime.NotImplemented(); + + public static void BfpProcess_GetMainWindowTitle(BfpProcess* process, char8* outTitle, int32* inOutTitleSize, BfpProcessResult* outResult) => Runtime.NotImplemented(); + + public static void BfpProcess_GetProcessName(BfpProcess* process, char8* outName, int32* inOutNameSize, BfpProcessResult* outResult) => Runtime.NotImplemented(); + + public static int32 BfpProcess_GetProcessId(BfpProcess* process) => Runtime.NotImplemented(); +#endif public enum BfpSpawnFlags : int32 { @@ -181,6 +275,7 @@ namespace System UnknownError = (int)Result.UnknownError }; +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpSpawn* BfpSpawn_Create(char8* targetPath, char8* args, char8* workingDir, char8* env, BfpSpawnFlags flags, BfpSpawnResult* outResult); [CallingConvention(.Stdcall), CLink] @@ -205,6 +300,47 @@ namespace System public static extern bool BfpCritSect_TryEnter(BfpCritSect* critSect, int32 waitMS); [CallingConvention(.Stdcall), CLink] public static extern void BfpCritSect_Leave(BfpCritSect* critSect); +#else + + public static BfpSpawn* BfpSpawn_Create(char8* targetPath, char8* args, char8* workingDir, char8* env, BfpSpawnFlags flags, BfpSpawnResult* outResult) + { + *outResult = .UnknownError; + return null; + } + + public static void BfpSpawn_Release(BfpSpawn* spawn) => Runtime.NotImplemented(); + + public static void BfpSpawn_Kill(BfpSpawn* spawn, int32 exitCode, BfpKillFlags killFlags, BfpSpawnResult* outResult) => Runtime.NotImplemented(); + + public static bool BfpSpawn_WaitFor(BfpSpawn* spawn, int waitMS, int* outExitCode, BfpSpawnResult* outResult) => Runtime.NotImplemented(); + + public static void BfpSpawn_GetStdHandles(BfpSpawn* spawn, BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) => Runtime.NotImplemented(); + + + public static int BfpProcess_GetCurrentId() => Runtime.NotImplemented(); + + public static BfpCritSect* BfpCritSect_Create() => new BfpCritSect(); + + public static void BfpCritSect_Release(BfpCritSect* critSect) + { + delete critSect; + } + + public static void BfpCritSect_Enter(BfpCritSect* critSect) + { + + } + + public static bool BfpCritSect_TryEnter(BfpCritSect* critSect, int32 waitMS) + { + return true; + } + + public static void BfpCritSect_Leave(BfpCritSect* critSect) + { + + } +#endif public enum BfpEventFlags : int32 { @@ -221,6 +357,7 @@ namespace System BfpEventResult_NotSupported = (int)Result.NotSupported }; +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpEvent* BfpEvent_Create(BfpEventFlags flags); [CallingConvention(.Stdcall), CLink] @@ -231,6 +368,46 @@ namespace System public static extern void BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern bool BfpEvent_WaitFor(BfpEvent* event, int32 waitMS); +#else + + public static BfpEvent* BfpEvent_Create(BfpEventFlags flags) + { + var result = new BfpEvent(); + result.mSet = flags.HasFlag(.InitiallySet_Auto) | flags.HasFlag(.InitiallySet_Manual); + result.mAuto = flags.HasFlag(.InitiallySet_Auto); + return result; + } + + public static void BfpEvent_Release(BfpEvent* event) + { + delete event; + } + + public static void BfpEvent_Set(BfpEvent* event, bool requireManualReset) + { + event.mSet = true; + event.mAuto = !requireManualReset; + } + + public static void BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult) + { + event.mSet = false; + event.mAuto = false; + *outResult = .BfpEventResult_Ok; + } + + public static bool BfpEvent_WaitFor(BfpEvent* event, int32 waitMS) + { + if (!event.mSet) + return false; + if (event.mAuto) + { + event.mSet = false; + event.mAuto = false; + } + return true; + } +#endif public enum BfpLibResult : int32 { @@ -239,6 +416,7 @@ namespace System InsufficientBuffer = (int)Result.InsufficientBuffer }; +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpDynLib* BfpDynLib_Load(char8* fileName); [CallingConvention(.Stdcall), CLink] @@ -247,6 +425,16 @@ namespace System public static extern void BfpDynLib_GetFilePath(BfpDynLib* lib, char8* outPath, int32* inOutPathSize, BfpLibResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern void* BfpDynLib_GetProcAddress(BfpDynLib* lib, char8* name); +#else + + public static BfpDynLib* BfpDynLib_Load(char8* fileName) => Runtime.NotImplemented(); + + public static void BfpDynLib_Release(BfpDynLib* lib) => Runtime.NotImplemented(); + + public static void BfpDynLib_GetFilePath(BfpDynLib* lib, char8* outPath, int32* inOutPathSize, BfpLibResult* outResult) => Runtime.NotImplemented(); + + public static void* BfpDynLib_GetProcAddress(BfpDynLib* lib, char8* name) => Runtime.NotImplemented(); +#endif public enum BfpFileResult : int32 { @@ -265,6 +453,7 @@ namespace System NotEmpty = (int)Result.NotEmpty, }; +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern void BfpDirectory_Create(char8* name, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] @@ -279,6 +468,22 @@ namespace System public static extern bool BfpDirectory_Exists(char8* path); [CallingConvention(.Stdcall), CLink] public static extern void BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char8* outPath, int32* inOutPathLen, BfpFileResult* outResult); +#else + + public static void BfpDirectory_Create(char8* name, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpDirectory_Rename(char8* oldName, char8* newName, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpDirectory_Delete(char8* name, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpDirectory_GetCurrent(char8* outPath, int32* inOutPathSize, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpDirectory_SetCurrent(char8* path, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static bool BfpDirectory_Exists(char8* path) => Runtime.NotImplemented(); + + public static void BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char8* outPath, int32* inOutPathLen, BfpFileResult* outResult) => Runtime.NotImplemented(); +#endif public enum BfpFileCreateKind : int32 { @@ -347,6 +552,7 @@ namespace System In } +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpFile* BfpFile_Create(char8* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] @@ -389,6 +595,50 @@ namespace System public static extern void BfpFile_GetFullPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern void BfpFile_GetActualPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult); +#else + + public static BfpFile* BfpFile_Create(char8* name, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static BfpFile* BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static int BfpFile_GetSystemHandle(BfpFile* file) => Runtime.NotImplemented(); + + public static void BfpFile_Release(BfpFile* file) => Runtime.NotImplemented(); + + public static int BfpFile_Write(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static int BfpFile_Read(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_Flush(BfpFile* file) => Runtime.NotImplemented(); + + public static int64 BfpFile_GetFileSize(BfpFile* file) => Runtime.NotImplemented(); + + public static int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind) => Runtime.NotImplemented(); + + public static void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path) => Runtime.NotImplemented(); + + public static BfpFileAttributes BfpFile_GetAttributes(char8* path, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_SetAttributes(char8* path, BfpFileAttributes attribs, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_Copy(char8* oldPath, char8* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_Rename(char8* oldPath, char8* newPath, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_Delete(char8* path, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static bool BfpFile_Exists(char8* path) => Runtime.NotImplemented(); + + public static void BfpFile_GetTempPath(char8* outPath, int32* inOutPathSize, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_GetTempFileName(char8* outName, int32* inOutNameSize, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_GetFullPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static void BfpFile_GetActualPath(char8* inPath, char8* outPath, int32* inOutPathSize, BfpFileResult* outResult) => Runtime.NotImplemented(); +#endif public enum BfpFindFileFlags : int32 { @@ -397,6 +647,7 @@ namespace System Directories = 2, }; +#if !BF_RUNTIME_DISABLE [CallingConvention(.Stdcall), CLink] public static extern BfpFindFileData* BfpFindFileData_FindFirstFile(char8* path, BfpFindFileFlags flags, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] @@ -415,6 +666,26 @@ namespace System public static extern int64 BfpFindFileData_GetFileSize(BfpFindFileData* findData); [CallingConvention(.Stdcall), CLink] public static extern void BfpFindFileData_Release(BfpFindFileData* findData); +#else + + public static BfpFindFileData* BfpFindFileData_FindFirstFile(char8* path, BfpFindFileFlags flags, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static bool BfpFindFileData_FindNextFile(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static void BfpFindFileData_GetFileName(BfpFindFileData* findData, char8* outName, int32* inOutNameSize, BfpFileResult* outResult) => Runtime.NotImplemented(); + + public static BfpTimeStamp BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static BfpTimeStamp BfpFindFileData_GetTime_Created(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static BfpTimeStamp BfpFindFileData_GetTime_Access(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static BfpFileAttributes BfpFindFileData_GetFileAttributes(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static int64 BfpFindFileData_GetFileSize(BfpFindFileData* findData) => Runtime.NotImplemented(); + + public static void BfpFindFileData_Release(BfpFindFileData* findData) => Runtime.NotImplemented(); +#endif public enum BfpSysDirectoryKind : int32 { diff --git a/BeefLibs/corlib/src/Pointer.bf b/BeefLibs/corlib/src/Pointer.bf index a5c95c74..a62cbedc 100644 --- a/BeefLibs/corlib/src/Pointer.bf +++ b/BeefLibs/corlib/src/Pointer.bf @@ -18,7 +18,7 @@ namespace System public override void ToString(String strBuffer) { - strBuffer.AppendF("0x{0:A}", (uint)(void*)mVal); + strBuffer.AppendF("0x{0:A}", (UInt.Simple)(uint)(void*)mVal); } } @@ -34,8 +34,8 @@ namespace System public override void ToString(String strBuffer) { strBuffer.Append("("); - typeof(T).GetFullName(strBuffer); - strBuffer.AppendF("*)0x{0:A}", (uint)(void*)mVal); + typeof(T).ToString(strBuffer); + strBuffer.AppendF("*)0x{0:A}", (UInt.Simple)(uint)(void*)mVal); } } } diff --git a/BeefLibs/corlib/src/Runtime.bf b/BeefLibs/corlib/src/Runtime.bf index cf2207ad..29709220 100644 --- a/BeefLibs/corlib/src/Runtime.bf +++ b/BeefLibs/corlib/src/Runtime.bf @@ -1,9 +1,11 @@ using System.Threading; using System.Collections; -#if BF_ENABLE_OBJECT_DEBUG_FLAGS || BF_DEBUG_ALLOC +#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 @@ -17,7 +19,7 @@ namespace System { const int32 cVersion = 10; - [CRepr, AlwaysInclude] + [CRepr] struct BfDebugMessageData { enum MessageType : int32 @@ -104,7 +106,7 @@ namespace System struct BfRtCallbacks { - public static BfRtCallbacks sCallbacks = .(); + public static BfRtCallbacks sCallbacks; function void* (int size) mAlloc; function void (void* ptr) mFree; @@ -115,7 +117,7 @@ namespace System 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 StringView (String str) mString_ToStringView; function Object () mThread_Alloc; function Object () mThread_GetMainThread; function void (Object thread) mThread_ThreadProc; @@ -178,7 +180,7 @@ namespace System static void Type_GetFullName(Type type, String str) { #if BF_DBG_RUNTIME - type.GetFullName(str); + type.ToString(str); #else // #endif @@ -189,9 +191,9 @@ namespace System return new String(); } - static char8* String_ToCStr(String str) + static StringView String_ToStringView(String str) { - return str.CStr(); + return str; } static void GC_MarkAllStaticMembers() @@ -219,39 +221,37 @@ namespace System 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 CheckErrorHandler(char8* kind, char8* arg1, char8* arg2, int arg3) + + static int32 CheckErrorHandle(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); + if (Runtime.CheckErrorHandler != null) + return Runtime.CheckErrorHandler(kind, arg1, arg2, arg3); + return 0; } public void Init() mut @@ -264,7 +264,7 @@ namespace System mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId; mType_GetFullName = => Type_GetFullName; mString_Alloc = => String_Alloc; - mString_ToCStr = => String_ToCStr; + mString_ToStringView = => String_ToStringView; mGC_MarkAllStaticMembers = => GC_MarkAllStaticMembers; mGC_CallRootCallbacks = => GC_CallRootCallbacks; mGC_Shutdown = => GC_Shutdown; @@ -277,12 +277,23 @@ namespace System } }; +#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 { @@ -359,18 +370,23 @@ namespace System Fail } - public delegate ErrorHandlerResult ErrorHandler(ErrorStage stage, Error error); + static struct ErrorHandlerData + { + public delegate ErrorHandlerResult ErrorHandler(ErrorStage stage, Error error); + public static AllocWrapper sMonitor ~ _.Dispose(); + public static List sErrorHandlers ~ DeleteContainerAndItems!(_); + public static bool sInsideErrorHandler; + } static RtFlags sExtraFlags; - static AllocWrapper sMonitor ~ _.Dispose(); - static List sErrorHandlers ~ DeleteContainerAndItems!(_); - static bool sInsideErrorHandler; - static bool sQueriedFeatures = false; static RuntimeFeatures sFeatures; + static function void() sThreadInit; + public static this() { +#if !BF_RUNTIME_DISABLE BfRtCallbacks.sCallbacks.Init(); RtFlags flags = sExtraFlags; @@ -384,84 +400,134 @@ namespace System 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 - Thread.[Friend]Init(); + if (sThreadInit != null) + sThreadInit(); +#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); +#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 .()..AppendF("Not Implemented at line {} in {}", line, filePath); + 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) + public static void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum) { if (!condition) { - if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Runtime, error, filePath, line)) == .Ignore) + if ((Runtime.CheckAssertError != null) && (Runtime.CheckAssertError(.Runtime, error, filePath, line) == .Ignore)) return; - String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath); +#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(ErrorHandler handler) + public static void AddErrorHandler(ErrorHandlerData.ErrorHandler handler) { if (Compiler.IsComptime) return; - using (sMonitor.Val.Enter()) + using (ErrorHandlerData.sMonitor.Val.Enter()) { - if (sErrorHandlers == null) - sErrorHandlers = new .(); - sErrorHandlers.Add(handler); + if (CheckAssertError == null) + { + CheckAssertError = => CheckAssertError_Impl; + CheckErrorHandler = => CheckErrorHandler_Impl; + } + + if (ErrorHandlerData.sErrorHandlers == null) + ErrorHandlerData.sErrorHandlers = new .(); + ErrorHandlerData.sErrorHandlers.Add(handler); } } - public static Result RemoveErrorHandler(ErrorHandler handler) + public static Result RemoveErrorHandler(ErrorHandlerData.ErrorHandler handler) { if (Compiler.IsComptime) return .Ok; - using (sMonitor.Val.Enter()) + using (ErrorHandlerData.sMonitor.Val.Enter()) { - if (sErrorHandlers.RemoveStrict(handler)) + if (ErrorHandlerData.sErrorHandlers.RemoveStrict(handler)) return .Ok; } return .Err; } - public static ErrorHandlerResult CheckErrorHandlers(Error error) + 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; + + 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 (sMonitor.Val.Enter()) + using (ErrorHandlerData.sMonitor.Val.Enter()) { - if (sInsideErrorHandler) + if (ErrorHandlerData.sInsideErrorHandler) return .ContinueFailure; - sInsideErrorHandler = true; - defer { sInsideErrorHandler = false; } + ErrorHandlerData.sInsideErrorHandler = true; + defer { ErrorHandlerData.sInsideErrorHandler = false; } for (int pass = 0; pass < 2; pass++) { - int idx = (sErrorHandlers?.Count).GetValueOrDefault() - 1; + int idx = (ErrorHandlerData.sErrorHandlers?.Count).GetValueOrDefault() - 1; while (idx >= 0) { - if (idx < sErrorHandlers.Count) + if (idx < ErrorHandlerData.sErrorHandlers.Count) { - var handler = sErrorHandlers[idx]; + var handler = ErrorHandlerData.sErrorHandlers[idx]; var result = handler((pass == 0) ? .PreFail : .Fail, error); if (result == .Ignore) { @@ -562,5 +628,122 @@ namespace System [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 +namespace System +{ + [AlwaysInclude, StaticInitPriority(1000)] + static class MinRuntime + { + static function void*(int) sMallocFunc; + static function void(void*) sFreeFunc; + + static this() + { + var lib = Windows.LoadLibraryA("msvcrt.dll"); + sMallocFunc = (.)Windows.GetProcAddress(lib, "malloc"); + sFreeFunc = (.)Windows.GetProcAddress(lib, "free"); + } + + /*[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 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() + { + //WinMain(null, null, "hi", 1); + main(0, null); + } + + [LinkName(.C), Export] + static int32 _tls_index; + + [LinkName(.C), Export] + static bool _fltused; + } +} +#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/Span.bf b/BeefLibs/corlib/src/Span.bf index c30753df..ae1d76f8 100644 --- a/BeefLibs/corlib/src/Span.bf +++ b/BeefLibs/corlib/src/Span.bf @@ -330,7 +330,7 @@ namespace System public override void ToString(String strBuffer) { strBuffer.Append("("); - typeof(T).GetFullName(strBuffer); + typeof(T).ToString(strBuffer); strBuffer.AppendF("*)0x{0:A}[{1}]", (uint)(void*)mPtr, mLength); } diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 04d3a8ec..c101c048 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -10,6 +10,8 @@ using System.Threading; using System.Interop; using System; +using internal System.String; + namespace System { // String size type @@ -46,6 +48,13 @@ namespace System NullTerminate = 1 } + internal struct Interns + { + public static Monitor sMonitor = new Monitor() ~ delete _; + public static HashSet sInterns = new .() ~ delete _; + public static List sOwnedInterns = new .() ~ DeleteContainerAndItems!(_); + } + int_strsize mLength; uint_strsize mAllocSizeAndFlags; char8* mPtrOrBuffer = null; @@ -53,9 +62,6 @@ namespace System extern const String* sStringLiterals; extern const String* sIdStringLiterals; static String* sPrevInternLinkPtr; // For detecting changes to sStringLiterals for hot loads - static Monitor sMonitor = new Monitor() ~ delete _; - static HashSet sInterns = new .() ~ delete _; - static List sOwnedInterns = new .() ~ DeleteContainerAndItems!(_); public const String Empty = ""; #if BF_LARGE_STRINGS @@ -619,7 +625,6 @@ namespace System String.Quote(Ptr, mLength, outString); } - [AlwaysInclude] public char8* CStr() { EnsureNullTerminator(); @@ -2846,15 +2851,15 @@ namespace System String str = *(ptr++); if (str == null) break; - sInterns.Add(str); + Interns.sInterns.Add(str); } } public String Intern() { - using (sMonitor.Enter()) + using (Interns.sMonitor.Enter()) { - bool needsLiteralPass = sInterns.Count == 0; + bool needsLiteralPass = Interns.sInterns.Count == 0; String* internalLinkPtr = *((String**)(sStringLiterals)); if (internalLinkPtr != sPrevInternLinkPtr) { @@ -2865,13 +2870,13 @@ namespace System CheckLiterals(sStringLiterals); String* entryPtr; - if (sInterns.TryAdd(this, out entryPtr)) + if (Interns.sInterns.TryAdd(this, out entryPtr)) { String result = new String(mLength + 1); result.Append(this); result.EnsureNullTerminator(); *entryPtr = result; - sOwnedInterns.Add(result); + Interns.sOwnedInterns.Add(result); return result; } return *entryPtr; @@ -4256,9 +4261,9 @@ namespace System public String Intern() { - using (String.[Friend]sMonitor.Enter()) + using (String.Interns.sMonitor.Enter()) { - bool needsLiteralPass = String.[Friend]sInterns.Count == 0; + bool needsLiteralPass = String.Interns.sInterns.Count == 0; String* internalLinkPtr = *((String**)(String.[Friend]sStringLiterals)); if (internalLinkPtr != String.[Friend]sPrevInternLinkPtr) { @@ -4269,13 +4274,13 @@ namespace System String.[Friend]CheckLiterals(String.[Friend]sStringLiterals); String* entryPtr; - if (String.[Friend]sInterns.TryAddAlt(this, out entryPtr)) + if (String.Interns.sInterns.TryAddAlt(this, out entryPtr)) { String result = new String(mLength + 1); result.Append(this); result.EnsureNullTerminator(); *entryPtr = result; - String.[Friend]sOwnedInterns.Add(result); + String.Interns.sOwnedInterns.Add(result); return result; } return *entryPtr; @@ -4367,7 +4372,7 @@ namespace System } #if TEST - extension String + class StringTest { [Test] public static void Test_Intern() diff --git a/BeefLibs/corlib/src/Test.bf b/BeefLibs/corlib/src/Test.bf index 2e73cb13..e82dc6db 100644 --- a/BeefLibs/corlib/src/Test.bf +++ b/BeefLibs/corlib/src/Test.bf @@ -70,7 +70,7 @@ namespace System { if (!condition) { - if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Test, error, filePath, line)) == .Ignore) + if ((Runtime.CheckAssertError != null) && (Runtime.CheckAssertError(.Test, error, filePath, line) == .Ignore)) return; String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath); Internal.[Friend]Test_Error(failStr); diff --git a/BeefLibs/corlib/src/Text/Encoding.bf b/BeefLibs/corlib/src/Text/Encoding.bf index 6ba2f20b..acbead21 100644 --- a/BeefLibs/corlib/src/Text/Encoding.bf +++ b/BeefLibs/corlib/src/Text/Encoding.bf @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Threading; namespace System.Text { [StaticInitPriority(100)] @@ -15,11 +16,39 @@ namespace System.Text case PartialEncode(int inChars, int encodedBytes); } - public static readonly ASCIIEncoding ASCII = new ASCIIEncoding() ~ delete _; - public static readonly UTF8Encoding UTF8 = new UTF8Encoding() ~ delete _; - public static readonly UTF8EncodingWithBOM UTF8WithBOM = new UTF8EncodingWithBOM() ~ delete _; - public static readonly UTF16Encoding UTF16 = new UTF16Encoding() ~ delete _; - public static readonly UTF16EncodingWithBOM UTF16WithBOM = new UTF16EncodingWithBOM() ~ delete _; + static Encoding sASCII ~ delete _; + static Encoding sUTF8 ~ delete _; + static Encoding sUTF8WithBOM ~ delete _; + static Encoding sUTF16 ~ delete _; + static Encoding sUTF16WithBOM ~ delete _; + + static T GetEncoding(ref Encoding encoding) where T : Encoding, new, delete + { + if (encoding != null) + return (.)encoding; + + var newEncoding = new T(); + if (Compiler.IsComptime) + { + encoding = newEncoding; + return newEncoding; + } + + let prevValue = Interlocked.CompareExchange(ref encoding, null, newEncoding); + if (prevValue != null) + { + // This was already set - race condition + delete newEncoding; + return (.)prevValue; + } + return newEncoding; + } + + public static ASCIIEncoding ASCII => GetEncoding(ref sASCII); + public static UTF8Encoding UTF8 => GetEncoding(ref sUTF8); + public static UTF8EncodingWithBOM UTF8WithBOM => GetEncoding(ref sUTF8WithBOM); + public static UTF16Encoding UTF16 => GetEncoding(ref sUTF16); + public static UTF16EncodingWithBOM UTF16WithBOM => GetEncoding(ref sUTF16WithBOM); public abstract int GetCharUnitSize(); public abstract int GetEncodedLength(char32 c); diff --git a/BeefLibs/corlib/src/Threading/Thread.bf b/BeefLibs/corlib/src/Threading/Thread.bf index e8c7fa93..b6fb4de6 100644 --- a/BeefLibs/corlib/src/Threading/Thread.bf +++ b/BeefLibs/corlib/src/Threading/Thread.bf @@ -26,7 +26,7 @@ namespace System.Threading static Event sOnExit ~ _.Dispose(); Event mOnExit ~ _.Dispose(); - public static Thread sMainThread = new Thread() ~ delete _; + public static Thread sMainThread ~ delete _; [StaticInitPriority(102)] struct RuntimeThreadInit @@ -48,8 +48,10 @@ namespace System.Threading static void Thread_SetInternalThread(Object thread, void* internalThread) { +#if BF_ENABLE_REALTIME_LEAK_CHECK if (internalThread != null) GC.[Friend]AddPendingThread(internalThread); +#endif ((Thread)thread).[Friend]mInternalThread = (int)internalThread; } @@ -118,9 +120,20 @@ namespace System.Threading cb.[Friend]mThread_AutoDelete = => Thread_AutoDelete; cb.[Friend]mThread_GetMaxStackSize = => Thread_GetMaxStackSize; cb.[Friend]mThread_Exiting = => Thread_Exiting; + + Runtime.[Friend, NoStaticCtor]sThreadInit = => Thread.Init; } + + public static void Check() + { + } } + public static this() + { + RuntimeThreadInit.Check(); + } + private this() { @@ -170,6 +183,7 @@ namespace System.Threading { #unwarn RuntimeThreadInit runtimeThreadInitRef = ?; + sMainThread = new Thread(); sMainThread.ManualThreadInit(); } @@ -225,11 +239,6 @@ namespace System.Threading } } - extern void ManualThreadInit(); - extern void StartInternal(); - extern void SetStackStart(void* ptr); - extern void ThreadStarted(); - public void Start(bool autoDelete = true) { mAutoDelete = autoDelete; @@ -247,7 +256,7 @@ namespace System.Threading StartInternal(); } -#if BF_PLATFORM_WINDOWS +#if BF_PLATFORM_WINDOWS && !BF_RUNTIME_DISABLE [CLink] static extern int32 _tls_index; #endif @@ -256,7 +265,7 @@ namespace System.Threading { get { -#if BF_PLATFORM_WINDOWS +#if BF_PLATFORM_WINDOWS && !BF_RUNTIME_DISABLE return _tls_index; #else return 0; @@ -264,10 +273,6 @@ namespace System.Threading } } - public static extern void RequestExitNotify(); - public extern void Suspend(); - public extern void Resume(); - public ThreadPriority Priority { get @@ -283,12 +288,7 @@ namespace System.Threading SetPriorityNative((int32)value); } } - [CallingConvention(.Cdecl)] - private extern int32 GetPriorityNative(); - [CallingConvention(.Cdecl)] - private extern void SetPriorityNative(int32 priority); - extern bool GetIsAlive(); public bool IsAlive { get @@ -297,8 +297,7 @@ namespace System.Threading } } - [CallingConvention(.Cdecl)] - extern bool GetIsThreadPoolThread(); + public bool IsThreadPoolThread { get @@ -307,8 +306,6 @@ namespace System.Threading } } - private extern bool JoinInternal(int32 millisecondsTimeout); - public void Join() { JoinInternal(Timeout.Infinite); @@ -328,7 +325,6 @@ namespace System.Threading return Join((int32)tm); } - private static extern void SleepInternal(int32 millisecondsTimeout); public static void Sleep(int32 millisecondsTimeout) { SleepInternal(millisecondsTimeout); @@ -342,15 +338,11 @@ namespace System.Threading Sleep((int32)tm); } - private static extern void SpinWaitInternal(int32 iterations); - public static void SpinWait(int iterations) { SpinWaitInternal((int32)iterations); } - private static extern bool YieldInternal(); - public static bool Yield() { return YieldInternal(); @@ -364,9 +356,6 @@ namespace System.Threading } } - [CallingConvention(.Cdecl)] - extern int GetThreadId(); - public int Id { get @@ -376,9 +365,6 @@ namespace System.Threading } public static int CurrentThreadId => Platform.BfpThread_GetCurrentId(); - - [CallingConvention(.Cdecl)] - private static extern Thread GetCurrentThreadNative(); void SetStart(Delegate ownStartDelegate, int32 maxStackSize) { @@ -405,18 +391,11 @@ namespace System.Threading delete mDelegate; } - [CallingConvention(.Cdecl)] - private extern void InternalFinalize(); - public bool IsBackground { get { return IsBackgroundNative(); } set { SetBackgroundNative(value); } } - [CallingConvention(.Cdecl)] - private extern bool IsBackgroundNative(); - [CallingConvention(.Cdecl)] - private extern void SetBackgroundNative(bool isBackground); public void SetJoinOnDelete(bool joinOnDelete) { @@ -427,8 +406,6 @@ namespace System.Threading { get { return (ThreadState)GetThreadStateNative(); } } - [CallingConvention(.Cdecl)] - private extern int32 GetThreadStateNative(); public void SetName(String name) { @@ -450,7 +427,63 @@ namespace System.Threading if (mName != null) outName.Append(mName); } + +#if !BF_RUNTIME_DISABLE [CallingConvention(.Cdecl)] private extern void InformThreadNameChange(String name); + [CallingConvention(.Cdecl)] + private extern bool IsBackgroundNative(); + [CallingConvention(.Cdecl)] + private extern void SetBackgroundNative(bool isBackground); + [CallingConvention(.Cdecl)] + private extern void InternalFinalize(); + [CallingConvention(.Cdecl)] + private static extern Thread GetCurrentThreadNative(); + [CallingConvention(.Cdecl)] + private extern int32 GetPriorityNative(); + [CallingConvention(.Cdecl)] + private extern void SetPriorityNative(int32 priority); + [CallingConvention(.Cdecl)] + extern bool GetIsThreadPoolThread(); + [CallingConvention(.Cdecl)] + extern int GetThreadId(); + [CallingConvention(.Cdecl)] + private extern int32 GetThreadStateNative(); + private static extern void SpinWaitInternal(int32 iterations); + private static extern void SleepInternal(int32 millisecondsTimeout); + private extern bool JoinInternal(int32 millisecondsTimeout); + private static extern bool YieldInternal(); + extern void ManualThreadInit(); + extern void StartInternal(); + extern void SetStackStart(void* ptr); + extern void ThreadStarted(); + public static extern void RequestExitNotify(); + public extern void Suspend(); + public extern void Resume(); + extern bool GetIsAlive(); +#else + private void InformThreadNameChange(String name) {} + private bool IsBackgroundNative() => false; + private void SetBackgroundNative(bool isBackground) {} + private void InternalFinalize() {} + private static Thread GetCurrentThreadNative() => null; + private int32 GetPriorityNative() => 0; + private void SetPriorityNative(int32 priority) {} + bool GetIsThreadPoolThread() => false; + int GetThreadId() => 0; + private int32 GetThreadStateNative() => 0; + private static void SpinWaitInternal(int32 iterations) {} + private static void SleepInternal(int32 millisecondsTimeout) {} + private bool JoinInternal(int32 millisecondsTimeout) => false; + private static bool YieldInternal() => false; + void ManualThreadInit() {} + void StartInternal() {} + void SetStackStart(void* ptr) {} + void ThreadStarted() {} + public static void RequestExitNotify() {} + public void Suspend() {} + public void Resume() {} + bool GetIsAlive() => false; +#endif } } diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 0b134109..ce04f9f9 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -7,12 +7,15 @@ namespace System { struct ClassVData { - public Type mType; + public int mType; +#if BF_32_BIT + public int mType2; +#endif // The rest of this structured is generated by the compiler, // including the vtable and interface slots } - [Ordered, AlwaysInclude(AssumeInstantiated=true)] + [Ordered, AlwaysInclude, Reflect(.Type)] public class Type { extern const Type* sTypes; @@ -647,7 +650,7 @@ namespace System { GetFullName(strBuffer); }*/ - + protected this() { } @@ -746,7 +749,12 @@ namespace System public override void ToString(String strBuffer) { +#if !BF_REFLECT_MINIMAL GetFullName(strBuffer); +#else + strBuffer.Append("Type#"); + mTypeId.ToString(strBuffer); +#endif } public struct Enumerator : IEnumerator @@ -767,11 +775,11 @@ namespace System return .Ok(type); } } - } + } } enum TypeCode : uint8 - { + { None, CharPtr, StringId, @@ -890,6 +898,7 @@ namespace System.Reflection public int32 mCustomAttributesIdx; } + [CRepr, AlwaysInclude] public struct InterfaceData { public TypeId mInterfaceType; @@ -926,7 +935,7 @@ namespace System.Reflection int32 mCustomAttributesIdx; TypeId mBaseType; TypeId mUnderlyingType; - TypeId mOuterType; + TypeId mOuterType; int32 mInheritanceId; int32 mInheritanceCount; @@ -1262,17 +1271,17 @@ namespace System.Reflection checkType = arrayType.UnderlyingType; continue; } - + checkType.GetFullName(strBuffer); break; } - + for (var size in sizes) { if (size == -1) strBuffer.Append("[?]"); else - strBuffer.AppendF($"[{size}]"); + strBuffer.AppendF($"[{(Int.Simple)size}]"); } } } @@ -1499,7 +1508,7 @@ namespace System.Reflection Protected = 0x0003, Public = 0x0006, // end member access mask - + // field contract attributes. Static = 0x0010, // Defined on type, else per instance. InitOnly = 0x0020, // Field may only be initialized, not written to after init. diff --git a/BeefLibs/corlib/src/UInt.bf b/BeefLibs/corlib/src/UInt.bf index 5e9bd284..4e43f5da 100644 --- a/BeefLibs/corlib/src/UInt.bf +++ b/BeefLibs/corlib/src/UInt.bf @@ -11,6 +11,14 @@ namespace System case InvalidChar(uint partialResult); } + public struct Simple : uint + { + public override void ToString(String strBuffer) + { + ((uint)this).ToString(strBuffer); + } + } + public const uint MaxValue = (sizeof(uint) == 8) ? 0xFFFFFFFFFFFFFFFFUL : 0xFFFFFFFFL; public const uint MinValue = 0; diff --git a/BeefLibs/corlib/src/UInt64.bf b/BeefLibs/corlib/src/UInt64.bf index 5301efa0..c12e1b7e 100644 --- a/BeefLibs/corlib/src/UInt64.bf +++ b/BeefLibs/corlib/src/UInt64.bf @@ -58,8 +58,6 @@ namespace System } } - static String sHexUpperChars = "0123456789ABCDEF"; - static String sHexLowerChars = "0123456789abcdef"; public void ToString(String outString, String format, IFormatProvider formatProvider) { if(format == null || format.IsEmpty) diff --git a/BeefRT/rt/BfObjects.h b/BeefRT/rt/BfObjects.h index d8573e58..81522e7e 100644 --- a/BeefRT/rt/BfObjects.h +++ b/BeefRT/rt/BfObjects.h @@ -26,7 +26,7 @@ enum BfObjectFlags : uint8 BfObjectFlag_StackAlloc = 0x08, BfObjectFlag_AppendAlloc = 0x10, BfObjectFlag_AllocInfo = 0x20, - BfObjectFlag_AllocInfo_Short= 0x40, + BfObjectFlag_AllocInfo_Short= 0x40, BfObjectFlag_Deleted = 0x80 }; @@ -36,7 +36,7 @@ enum BfRtFlags BfRtFlags_LeakCheck = 2, BfRtFlags_SilentCrash = 4, BfRtFlags_DebugAlloc = 8, - BfRtFlags_NoThreadExitWait = 0x10, + BfRtFlags_NoThreadExitWait = 0x10, }; namespace bf @@ -90,7 +90,7 @@ namespace bf bf::System::Object* (*Object_DynamicCastToTypeId)(bf::System::Object* obj, int typeId); void(*Type_GetFullName)(System::Type* type, bf::System::String* str); bf::System::String* (*String_Alloc)(); - const char* (*String_ToCStr)(bf::System::String* str); + Beefy::StringView (*String_ToStringView)(bf::System::String* str); bf::System::Threading::Thread* (*Thread_Alloc)(); bf::System::Threading::Thread* (*Thread_GetMainThread)(); void(*Thread_ThreadProc)(bf::System::Threading::Thread* thread); @@ -98,24 +98,26 @@ namespace bf void(*Thread_SetInternalThread)(bf::System::Threading::Thread* thread, BfInternalThread* internalThread); bool(*Thread_IsAutoDelete)(bf::System::Threading::Thread* thread); void(*Thread_AutoDelete)(bf::System::Threading::Thread* thread); - int32(*Thread_GetMaxStackSize)(bf::System::Threading::Thread* thread); + int32(*Thread_GetMaxStackSize)(bf::System::Threading::Thread* thread); void(*Thread_Exiting)(); void(*GC_MarkAllStaticMembers)(); bool(*GC_CallRootCallbacks)(); void(*GC_Shutdown)(); void(*SetErrorString)(const char* str); void(*DebugMessageData_SetupError)(const char* str, int32 stackWindbackCount); - void(*DebugMessageData_SetupProfilerCmd)(const char* str); + void(*DebugMessageData_SetupProfilerCmd)(const char* str); void(*DebugMessageData_Fatal)(); void(*DebugMessageData_Clear)(); - int(*CheckErrorHandler)(const char* kind, const char* arg1, const char* arg2, intptr arg3); + int(*CheckErrorHandler)(const char* kind, const char* arg1, const char* arg2, intptr arg3); }; public: - BFRT_EXPORT static void SetCrashReportKind(RtCrashReportKind crashReportKind); + BFRT_EXPORT static void SetCrashReportKind(RtCrashReportKind crashReportKind); private: - BFRT_EXPORT static void Init(int version, int flags, BfRtCallbacks* callbacks); + BFRT_EXPORT static void Init(int version, int flags, BfRtCallbacks* callbacks); + BFRT_EXPORT static void InitCrashCatcher(int flags); + BFRT_EXPORT static void ShutdownCrashCatcher(); BFRT_EXPORT static void AddCrashInfoFunc(void* func); BFRT_EXPORT static void SetErrorString(char* errorStr); BFRT_EXPORT static void Dbg_Init(int version, int flags, BfRtCallbacks* callbacks); @@ -150,7 +152,7 @@ namespace bf public: union { - intptr mClassVData; + intptr mClassVData; struct { BfObjectFlags mObjectFlags; @@ -193,7 +195,7 @@ namespace bf TypeId mTypeId; TypeId mBoxedId; uint16 mTypeFlags; - int32 mMemberDataOffset; + int32 mMemberDataOffset; uint8 mTypeCode; uint8 mAlign; @@ -225,7 +227,7 @@ namespace bf String* mName; String* mNamespace; int32 mInstSize; - int32 mInstAlign; + int32 mInstAlign; }; } @@ -252,9 +254,9 @@ namespace bf uint mAllocSizeAndFlags; char* mPtr; - const char* CStr() + Beefy::StringView ToStringView() { - return BFRTCALLBACKS.String_ToCStr(this); + return BFRTCALLBACKS.String_ToStringView(this); } }; } diff --git a/BeefRT/rt/Internal.cpp b/BeefRT/rt/Internal.cpp index 63762dba..ac0c0d13 100644 --- a/BeefRT/rt/Internal.cpp +++ b/BeefRT/rt/Internal.cpp @@ -52,6 +52,7 @@ USING_NS_BF; static Beefy::StringT<0> gCmdLineString; +bool gCmdLineStringHandled; bf::System::Runtime::BfRtCallbacks gBfRtCallbacks; BfRtFlags gBfRtFlags = (BfRtFlags)0; @@ -65,7 +66,10 @@ static int gTestMethodIdx = -1; static uint32 gTestStartTick = 0; static bool gTestBreakOnFailure = false; +typedef void(*ClientPipeErrorFunc)(const Beefy::StringView& error, int stackOffset); + static BfpFile* gClientPipe = NULL; +static ClientPipeErrorFunc gClientPipeErrorFunc; static Beefy::String gTestInBuffer; namespace bf @@ -85,7 +89,7 @@ namespace bf BFRT_EXPORT static void BfStaticCtor(); BFRT_EXPORT static void BfStaticDtor(); - BFRT_EXPORT static void Shutdown(); + BFRT_EXPORT static void Shutdown_Internal(); public: BFRT_EXPORT static Object* UnsafeCastToObject(void* inPtr); BFRT_EXPORT static void* UnsafeCastToPtr(Object* obj); @@ -224,18 +228,8 @@ 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"; - str += error; - str.Replace('\n', '\r'); - str += "\n"; - TestString(str); - - Beefy::String result; - TestReadCmd(result); - exit(1); - } + if (gClientPipeErrorFunc != NULL) + gClientPipeErrorFunc(error, 0); else BfpSystem_FatalError(error, "BEEF FATAL ERROR"); } @@ -304,57 +298,22 @@ void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks) if ((flags & 4) != 0) sysInitFlags = (BfpSystemInitFlags)(sysInitFlags | BfpSystemInitFlag_SilentCrash); BfpSystem_Init(BFP_VERSION, sysInitFlags); - BfpSystem_AddCrashInfoFunc(GetCrashInfo); if (gBfRtCallbacks.Alloc != NULL) { - Internal_FatalError(StrFormat("BeefRT already initialized. Multiple executable modules in the same process cannot dynamically link to the Beef runtime.").c_str()); + Internal_FatalError("BeefRT already initialized. Multiple executable modules in the same process cannot dynamically link to the Beef runtime."); } if (version != BFRT_VERSION) { - BfpSystem_FatalError(StrFormat("BeefRT build version '%d' does not match requested version '%d'", BFRT_VERSION, version).c_str(), "BEEF FATAL ERROR"); + char error[256]; + sprintf(error, "BeefRT build version '%d' does not match requested version '%d'", BFRT_VERSION, version); + BfpSystem_FatalError(error, "BEEF FATAL ERROR"); } gBfRtCallbacks = *callbacks; gBfRtFlags = (BfRtFlags)flags; - Beefy::String cmdLine; - - BfpSystemResult result; - BFP_GETSTR_HELPER(cmdLine, result, BfpSystem_GetCommandLine(__STR, __STRLEN, &result)); - - char* cmdLineStr = (char*)cmdLine.c_str(); - - //::MessageBoxA(NULL, cmdLineStr, "BFRT", 0); - - char* useCmdLineStr = cmdLineStr; - - if (cmdLineStr[0] != 0) - { - bool nameQuoted = cmdLineStr[0] == '\"'; - - Beefy::String passedName; - int i; - for (i = (nameQuoted ? 1 : 0); cmdLineStr[i] != 0; i++) - { - wchar_t c = cmdLineStr[i]; - - if (((nameQuoted) && (c == '"')) || - ((!nameQuoted) && (c == ' '))) - { - i++; - break; - } - passedName += cmdLineStr[i]; - } - - useCmdLineStr += i; - while (*useCmdLineStr == L' ') - useCmdLineStr++; - } - gCmdLineString = useCmdLineStr; - #ifdef BF_PLATFORM_WINDOWS gBfTLSKey = FlsAlloc(TlsFreeFunc); #else @@ -362,6 +321,20 @@ void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks) #endif } +void bf::System::Runtime::InitCrashCatcher(int flags) +{ + BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher; + if ((flags & 4) != 0) + sysInitFlags = (BfpSystemInitFlags)(sysInitFlags | BfpSystemInitFlag_SilentCrash); + BfpSystem_InitCrashCatcher(sysInitFlags); + BfpSystem_AddCrashInfoFunc(GetCrashInfo); +} + +void bf::System::Runtime::ShutdownCrashCatcher() +{ + BfpSystem_ShutdownCrashCatcher(); +} + void bf::System::Runtime::SetErrorString(char* errorStr) { ::SetErrorString(errorStr); @@ -379,7 +352,7 @@ void bf::System::Runtime::SetCrashReportKind(bf::System::Runtime::RtCrashReportK ////////////////////////////////////////////////////////////////////////// -void Internal::Shutdown() +void Internal::Shutdown_Internal() { BfInternalThread::WaitForAllDone(); if (gBfRtCallbacks.GC_Shutdown != NULL) @@ -419,20 +392,9 @@ void* Internal::UnsafeCastToPtr(Object* obj) void Internal::ThrowIndexOutOfRange(intptr stackOffset) { - if (gClientPipe != NULL) - { - if (gTestBreakOnFailure) - { - SETUP_ERROR("Index out of range", (int)(2 + stackOffset)); - BF_DEBUG_BREAK(); - } - - Beefy::String str = ":TestFail\tIndex out of range\n"; - TestString(str); - exit(1); - } - - if ((stackOffset != -1) && (::IsDebuggerPresent())) + if (gClientPipeErrorFunc != NULL) + gClientPipeErrorFunc("Index out of range", 0); + else if ((stackOffset != -1) && (::IsDebuggerPresent())) { SETUP_ERROR("Index out of range", (int)(2 + stackOffset)); BF_DEBUG_BREAK(); @@ -443,20 +405,9 @@ void Internal::ThrowIndexOutOfRange(intptr stackOffset) void Internal::ThrowObjectNotInitialized(intptr stackOffset) { - if (gClientPipe != NULL) - { - if (gTestBreakOnFailure) - { - SETUP_ERROR("Object not initialized", (int)(2 + stackOffset)); - BF_DEBUG_BREAK(); - } - - Beefy::String str = ":TestFail\tObject not initialized\n"; - TestString(str); - exit(1); - } - - if ((stackOffset != -1) && (::IsDebuggerPresent())) + if (gClientPipeErrorFunc != NULL) + gClientPipeErrorFunc("Object not initialized", 0); + else if ((stackOffset != -1) && (::IsDebuggerPresent())) { SETUP_ERROR("Object not initialized", (int)(2 + stackOffset)); BF_DEBUG_BREAK(); @@ -467,29 +418,17 @@ void Internal::ThrowObjectNotInitialized(intptr stackOffset) void Internal::FatalError(bf::System::String* error, intptr stackOffset) { - if (gClientPipe != NULL) - { - if (gTestBreakOnFailure) - { - SETUP_ERROR(error->CStr(), (int)(2 + stackOffset)); - BF_DEBUG_BREAK(); - } - - Beefy::String str = ":TestFail\t"; - str += error->CStr(); - str.Replace('\n', '\r'); - str += "\n"; - TestString(str); - exit(1); - } - + Beefy::StringView errorStringView = error->ToStringView(); + Beefy::StringSimple errorString = errorStringView; + if (gClientPipeErrorFunc != NULL) + gClientPipeErrorFunc(errorStringView, 0); if ((stackOffset != -1) && (::IsDebuggerPresent())) { - SETUP_ERROR(error->CStr(), (int)(2 + stackOffset)); + SETUP_ERROR(errorString.c_str(), (int)(2 + stackOffset)); BF_DEBUG_BREAK(); } - Internal_FatalError(error->CStr()); + Internal_FatalError(errorString.c_str()); } void Internal::MemCpy(void* dest, void* src, intptr length) @@ -630,6 +569,46 @@ void Internal::GetSharedProcAddressInto(void* libHandle, char* procName, void** char* Internal::GetCommandLineArgs() { + if (!gCmdLineStringHandled) + { + Beefy::String cmdLine; + + BfpSystemResult result; + BFP_GETSTR_HELPER(cmdLine, result, BfpSystem_GetCommandLine(__STR, __STRLEN, &result)); + + char* cmdLineStr = (char*)cmdLine.c_str(); + + //::MessageBoxA(NULL, cmdLineStr, "BFRT", 0); + + char* useCmdLineStr = cmdLineStr; + + if (cmdLineStr[0] != 0) + { + bool nameQuoted = cmdLineStr[0] == '\"'; + + Beefy::String passedName; + int i; + for (i = (nameQuoted ? 1 : 0); cmdLineStr[i] != 0; i++) + { + wchar_t c = cmdLineStr[i]; + + if (((nameQuoted) && (c == '"')) || + ((!nameQuoted) && (c == ' '))) + { + i++; + break; + } + passedName += cmdLineStr[i]; + } + + useCmdLineStr += i; + while (*useCmdLineStr == L' ') + useCmdLineStr++; + } + gCmdLineString = useCmdLineStr; + gCmdLineStringHandled = true; + } + return (char*)gCmdLineString.c_str(); } @@ -697,6 +676,27 @@ static void TestReadCmd(Beefy::String& str) } } +void TestFailed(const Beefy::StringView& error, int stackOffset) +{ + if (gClientPipe != NULL) + { + Beefy::String errorString = error; + + if (gTestBreakOnFailure) + { + SETUP_ERROR(errorString.c_str(), (int)(2 + stackOffset)); + BF_DEBUG_BREAK(); + } + + Beefy::String str = ":TestFail\t"; + str += errorString.c_str(); + str.Replace('\n', '\r'); + str += "\n"; + TestString(str); + exit(1); + } +} + void Internal::Test_Init(char* testData) { BfpSystem_SetCrashReportKind(BfpCrashReportKind_None); @@ -708,6 +708,8 @@ void Internal::Test_Init(char* testData) if (fileResult != BfpFileResult_Ok) BF_FATAL("Test_Init failed to create pipe to test manager"); + gClientPipeErrorFunc = TestFailed; + Beefy::String outStr; outStr += ":TestInit\n"; outStr += testData; @@ -853,7 +855,6 @@ void Internal::ObjectDynCheck(bf::System::Object* object, int typeId, bool allow if (result == NULL) { Beefy::String errorStr = "Attempting invalid cast on object"; - //errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, object->GetTypeName().c_str(), object); errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, "System.Object", object); SETUP_ERROR(errorStr.c_str(), 2); BF_DEBUG_BREAK(); diff --git a/BeefRT/rt/Object.cpp b/BeefRT/rt/Object.cpp index f2f3e09d..f8c7c002 100644 --- a/BeefRT/rt/Object.cpp +++ b/BeefRT/rt/Object.cpp @@ -7,7 +7,7 @@ Beefy::String bf::System::Object::GetTypeName() String* strObj = BFRTCALLBACKS.String_Alloc(); Type* type = _GetType(); BFRTCALLBACKS.Type_GetFullName(type, strObj); - Beefy::String str = strObj->CStr(); + Beefy::String str = strObj->ToStringView(); BFRTCALLBACKS.Object_Delete(strObj); return str; } @@ -16,7 +16,7 @@ Beefy::String bf::System::Type::GetFullName() { String* strObj = BFRTCALLBACKS.String_Alloc(); BFRTCALLBACKS.Type_GetFullName(this, strObj); - Beefy::String str = strObj->CStr(); + Beefy::String str = strObj->ToStringView(); BFRTCALLBACKS.Object_Delete(strObj); return str; } diff --git a/BeefRT/rt/Thread.cpp b/BeefRT/rt/Thread.cpp index 37114d63..b006c372 100644 --- a/BeefRT/rt/Thread.cpp +++ b/BeefRT/rt/Thread.cpp @@ -1,4 +1,4 @@ -#include "BeefySysLib/Common.h" +#include "BeefySysLib/Common.h" #include "BfObjects.h" #include "Thread.h" //#include "ThreadLocalStorage.h" @@ -32,24 +32,24 @@ bf::System::Threading::Thread* BfGetCurrentThread() #else Thread* internalThread = (Thread*)BfpTLS_GetValue(BfTLSManager::sInternalThreadKey); return internalThread; -#endif +#endif } void Thread::Suspend() { - BfpThread_Suspend(GetInternalThread()->mThreadHandle, NULL); + BfpThread_Suspend(GetInternalThread()->mThreadHandle, NULL); } void Thread::Resume() { - BfpThread_Resume(GetInternalThread()->mThreadHandle, NULL); + BfpThread_Resume(GetInternalThread()->mThreadHandle, NULL); } void Thread::SetJoinOnDelete(bool joinOnDelete) { - auto internalThread = GetInternalThread(); - Beefy::AutoCrit autoCrit(internalThread->mCritSect); - internalThread->mJoinOnDelete = joinOnDelete; + auto internalThread = GetInternalThread(); + Beefy::AutoCrit autoCrit(internalThread->mCritSect); + internalThread->mJoinOnDelete = joinOnDelete; } int Thread::GetPriorityNative() @@ -59,7 +59,7 @@ int Thread::GetPriorityNative() void Thread::SetPriorityNative(int priority) { - return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)(priority - 2), NULL); + return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)(priority - 2), NULL); } bool Thread::GetIsAlive() @@ -80,7 +80,7 @@ bool Thread::JoinInternal(int millisecondsTimeout) auto internalThread = GetInternalThread(); if (internalThread == NULL) return true; - bool success = BfpThread_WaitFor(internalThread->mThreadHandle, millisecondsTimeout); + bool success = BfpThread_WaitFor(internalThread->mThreadHandle, millisecondsTimeout); return success; } @@ -121,7 +121,7 @@ static void BF_CALLTYPE CStartProc(void* threadParam) #endif auto internalThread = thread->GetInternalThread(); - + // Hold lock until we get ThreadStarted callback internalThread->mCritSect.Lock(); @@ -130,16 +130,16 @@ static void BF_CALLTYPE CStartProc(void* threadParam) internalThread->mStackStart = (intptr)&thread; internalThread->ThreadStarted(); - bool isAutoDelete = gBfRtCallbacks.Thread_IsAutoDelete(thread); + bool isAutoDelete = gBfRtCallbacks.Thread_IsAutoDelete(thread); gBfRtCallbacks.Thread_ThreadProc(thread); bool isLastThread = BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, -1) == 1; //printf("Stopping thread\n"); - + bool wantsDelete = false; // - { - internalThread->ThreadStopped(); + { + internalThread->ThreadStopped(); Beefy::AutoCrit autoCrit(internalThread->mCritSect); if (isAutoDelete) @@ -149,8 +149,8 @@ static void BF_CALLTYPE CStartProc(void* threadParam) if (internalThread->mThread == NULL) { - // If the thread was already deleted then we need to delete ourselves now - wantsDelete = true; + // If the thread was already deleted then we need to delete ourselves now + wantsDelete = true; } } @@ -164,53 +164,53 @@ static void BF_CALLTYPE CStartProc(void* threadParam) } void BfInternalThread::WaitForAllDone() -{ +{ if ((gBfRtFlags & BfRtFlags_NoThreadExitWait) != 0) return; while (gLiveThreadCount != 0) { // Clear out any old done events - gThreadsDoneEvent.WaitFor(); + gThreadsDoneEvent.WaitFor(); } } BfInternalThread* Thread::SetupInternalThread() { - BfInternalThread* internalThread; + BfInternalThread* internalThread; internalThread = new BfInternalThread(); - SetInternalThread(internalThread); + SetInternalThread(internalThread); return internalThread; } void Thread::ManualThreadInit() -{ +{ #ifdef BF_THREAD_TLS sCurrentThread = this; #else BfpTLS_SetValue(BfTLSManager::sInternalThreadKey, this); #endif - + BfInternalThread* internalThread = SetupInternalThread(); internalThread->ManualThreadInit(this); } void Thread::StartInternal() -{ +{ BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, 1); BfInternalThread* internalThread = SetupInternalThread(); - + Beefy::AutoCrit autoCrit(internalThread->mCritSect); internalThread->mStarted = true; internalThread->mThread = this; #ifdef _WIN32 internalThread->mThreadHandle = BfpThread_Create(CStartProc, (void*)this, GetMaxStackSize(), (BfpThreadCreateFlags)(BfpThreadCreateFlag_StackSizeReserve | BfpThreadCreateFlag_Suspended), &internalThread->mThreadId); - SetInternalThread(internalThread); + SetInternalThread(internalThread); BfpThread_Resume(internalThread->mThreadHandle, NULL); #else internalThread->mThreadHandle = BfpThread_Create(CStartProc, (void*)this, GetMaxStackSize(), (BfpThreadCreateFlags)(BfpThreadCreateFlag_StackSizeReserve), &internalThread->mThreadId); - SetInternalThread(internalThread); + SetInternalThread(internalThread); #endif } @@ -220,9 +220,9 @@ void Thread::RequestExitNotify() if (BfGetCurrentThread() != NULL) return; -#ifdef BF_PLATFORM_WINDOWS +#ifdef BF_PLATFORM_WINDOWS FlsSetValue(gBfTLSKey, (void*)&gBfRtCallbacks); -#else +#else pthread_setspecific(gBfTLSKey, (void*)&gBfRtCallbacks); #endif } @@ -249,7 +249,7 @@ void Thread::InternalFinalize() auto internalThread = GetInternalThread(); if (internalThread == NULL) return; - + bool wantsJoin = false; bool started = false; @@ -264,12 +264,12 @@ void Thread::InternalFinalize() // { - Beefy::AutoCrit autoCrit(internalThread->mCritSect); + Beefy::AutoCrit autoCrit(internalThread->mCritSect); if ((!internalThread->mDone) && (internalThread->mJoinOnDelete)) { if (this != BfGetCurrentThread()) { - wantsJoin = true; + wantsJoin = true; } } } @@ -278,19 +278,19 @@ void Thread::InternalFinalize() JoinInternal(0); bool wantsDelete = false; - // + // { Beefy::AutoCrit autoCrit(internalThread->mCritSect); - + if (!internalThread->mDone) { // We need to let the internal thread delete itself when it's done... internalThread->mThread = NULL; } else - { - wantsDelete = true; - } + { + wantsDelete = true; + } SetInternalThread(NULL); } @@ -298,7 +298,7 @@ void Thread::InternalFinalize() wantsDelete = true; if (wantsDelete) - delete internalThread; + delete internalThread; } bool Thread::IsBackgroundNative() @@ -317,8 +317,11 @@ int Thread::GetThreadStateNative() } void Thread::InformThreadNameChange(String* name) -{ - BfpThread_SetName(GetInternalThread()->mThreadHandle, (name != NULL) ? name->CStr() : "", NULL); +{ + Beefy::String nameStr; + if (name != NULL) + nameStr = name->ToStringView(); + BfpThread_SetName(GetInternalThread()->mThreadHandle, nameStr.c_str(), NULL); } void Thread::MemoryBarrier() diff --git a/BeefySysLib/platform/PlatformInterface.h b/BeefySysLib/platform/PlatformInterface.h index 7fdd6ecc..c470544c 100644 --- a/BeefySysLib/platform/PlatformInterface.h +++ b/BeefySysLib/platform/PlatformInterface.h @@ -100,12 +100,14 @@ enum BfpCrashReportKind }; BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags); +BFP_EXPORT void BFP_CALLTYPE BfpSystem_InitCrashCatcher(BfpSystemInitFlags flags); BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv); BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind); BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc); BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str); // Can do at any time, or during CrashInfoFunc callbacks BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashRelaunchCmd(const char* str); BFP_EXPORT void BFP_CALLTYPE BfpSystem_Shutdown(); +BFP_EXPORT void BFP_CALLTYPE BfpSystem_ShutdownCrashCatcher(); BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_TickCount(); BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpSystem_GetTimeStamp(); BFP_EXPORT uint16 BFP_CALLTYPE BfpSystem_EndianSwap16(uint16 val); diff --git a/BeefySysLib/platform/win/CrashCatcher.cpp b/BeefySysLib/platform/win/CrashCatcher.cpp index 80a56ca6..d640cb56 100644 --- a/BeefySysLib/platform/win/CrashCatcher.cpp +++ b/BeefySysLib/platform/win/CrashCatcher.cpp @@ -52,7 +52,6 @@ static SYMGETMODULEBASEPROC gSymGetModuleBase = NULL; static SYMGETSYMFROMADDRPROC gSymGetSymFromAddr = NULL; static SYMGETLINEFROMADDR gSymGetLineFromAddr = NULL; - static bool CreateMiniDump(EXCEPTION_POINTERS* pep, const StringImpl& filePath); static bool LoadImageHelp() @@ -117,47 +116,6 @@ static bool LoadImageHelp() return true; } -struct -{ - DWORD dwExceptionCode; - char *szMessage; -} gMsgTable[] = { - { STATUS_SEGMENT_NOTIFICATION, "Segment Notification" }, - { STATUS_BREAKPOINT, "Breakpoint" }, - { STATUS_SINGLE_STEP, "Single step" }, - { STATUS_WAIT_0, "Wait 0" }, - { STATUS_ABANDONED_WAIT_0, "Abandoned Wait 0" }, - { STATUS_USER_APC, "User APC" }, - { STATUS_TIMEOUT, "Timeout" }, - { STATUS_PENDING, "Pending" }, - { STATUS_GUARD_PAGE_VIOLATION, "Guard Page Violation" }, - { STATUS_DATATYPE_MISALIGNMENT, "Data Type Misalignment" }, - { STATUS_ACCESS_VIOLATION, "Access Violation" }, - { STATUS_IN_PAGE_ERROR, "In Page Error" }, - { STATUS_NO_MEMORY, "No Memory" }, - { STATUS_ILLEGAL_INSTRUCTION, "Illegal Instruction" }, - { STATUS_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception" }, - { STATUS_INVALID_DISPOSITION, "Invalid Disposition" }, - { STATUS_ARRAY_BOUNDS_EXCEEDED, "Array Bounds Exceeded" }, - { STATUS_FLOAT_DENORMAL_OPERAND, "Float Denormal Operand" }, - { STATUS_FLOAT_DIVIDE_BY_ZERO, "Divide by Zero" }, - { STATUS_FLOAT_INEXACT_RESULT, "Float Inexact Result" }, - { STATUS_FLOAT_INVALID_OPERATION, "Float Invalid Operation" }, - { STATUS_FLOAT_OVERFLOW, "Float Overflow" }, - { STATUS_FLOAT_STACK_CHECK, "Float Stack Check" }, - { STATUS_FLOAT_UNDERFLOW, "Float Underflow" }, - { STATUS_INTEGER_DIVIDE_BY_ZERO, "Integer Divide by Zero" }, - { STATUS_INTEGER_OVERFLOW, "Integer Overflow" }, - { STATUS_PRIVILEGED_INSTRUCTION, "Privileged Instruction" }, - { STATUS_STACK_OVERFLOW, "Stack Overflow" }, - { STATUS_CONTROL_C_EXIT, "Ctrl+C Exit" }, - { 0xFFFFFFFF, "" } -}; - -static HFONT gDialogFont; -static HFONT gBoldFont; -static String gErrorTitle; -static String gErrorText; static HWND gDebugButtonWindow = NULL; static HWND gYesButtonWindow = NULL; static HWND gNoButtonWindow = NULL; @@ -265,19 +223,19 @@ static void ShowErrorDialog(const StringImpl& errorTitle, const StringImpl& erro gUseDefaultFonts = aVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT; int aHeight = -MulDiv(8, 96, 72); - gDialogFont = ::CreateFontA(aHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, + HFONT gDialogFont = ::CreateFontA(aHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Tahoma"); aHeight = -MulDiv(10, 96, 72); - gBoldFont = ::CreateFontA(aHeight, 0, 0, 0, FW_BOLD, FALSE, FALSE, + HFONT gBoldFont = ::CreateFontA(aHeight, 0, 0, 0, FW_BOLD, FALSE, FALSE, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Tahoma"); ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); - gErrorTitle = errorTitle; - gErrorText = errorText; + String gErrorTitle = errorTitle; + String gErrorText = errorText; WNDCLASSW wc; wc.style = 0; @@ -935,6 +893,44 @@ static void DoHandleDebugEvent(LPEXCEPTION_POINTERS lpEP) /////////////////////////// // first name the exception + + struct + { + DWORD dwExceptionCode; + char* szMessage; + } gMsgTable[] = { + { STATUS_SEGMENT_NOTIFICATION, "Segment Notification" }, + { STATUS_BREAKPOINT, "Breakpoint" }, + { STATUS_SINGLE_STEP, "Single step" }, + { STATUS_WAIT_0, "Wait 0" }, + { STATUS_ABANDONED_WAIT_0, "Abandoned Wait 0" }, + { STATUS_USER_APC, "User APC" }, + { STATUS_TIMEOUT, "Timeout" }, + { STATUS_PENDING, "Pending" }, + { STATUS_GUARD_PAGE_VIOLATION, "Guard Page Violation" }, + { STATUS_DATATYPE_MISALIGNMENT, "Data Type Misalignment" }, + { STATUS_ACCESS_VIOLATION, "Access Violation" }, + { STATUS_IN_PAGE_ERROR, "In Page Error" }, + { STATUS_NO_MEMORY, "No Memory" }, + { STATUS_ILLEGAL_INSTRUCTION, "Illegal Instruction" }, + { STATUS_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception" }, + { STATUS_INVALID_DISPOSITION, "Invalid Disposition" }, + { STATUS_ARRAY_BOUNDS_EXCEEDED, "Array Bounds Exceeded" }, + { STATUS_FLOAT_DENORMAL_OPERAND, "Float Denormal Operand" }, + { STATUS_FLOAT_DIVIDE_BY_ZERO, "Divide by Zero" }, + { STATUS_FLOAT_INEXACT_RESULT, "Float Inexact Result" }, + { STATUS_FLOAT_INVALID_OPERATION, "Float Invalid Operation" }, + { STATUS_FLOAT_OVERFLOW, "Float Overflow" }, + { STATUS_FLOAT_STACK_CHECK, "Float Stack Check" }, + { STATUS_FLOAT_UNDERFLOW, "Float Underflow" }, + { STATUS_INTEGER_DIVIDE_BY_ZERO, "Integer Divide by Zero" }, + { STATUS_INTEGER_OVERFLOW, "Integer Overflow" }, + { STATUS_PRIVILEGED_INSTRUCTION, "Privileged Instruction" }, + { STATUS_STACK_OVERFLOW, "Stack Overflow" }, + { STATUS_CONTROL_C_EXIT, "Ctrl+C Exit" }, + { 0xFFFFFFFF, "" } + }; + char *szName = NULL; for (int i = 0; gMsgTable[i].dwExceptionCode != 0xFFFFFFFF; i++) { diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index a1ae8170..dbda54d2 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -39,9 +39,14 @@ USING_NS_BF; +static void Crash_Error(const char* msg); + +typedef void(*BfpCrashErrorFunc)(const char* str); + static bool gTimerInitialized = false; static int gTimerDivisor = 0; CritSect gBfpCritSect; +BfpCrashErrorFunc gCrashErrorFunc = Crash_Error; struct WindowsSharedInfo { @@ -415,8 +420,9 @@ void Beefy::BFFatalError(const StringImpl& message, const StringImpl& file, int gBFApp->mSysDialogCnt++; #endif - String failMsg = StrFormat("%s in %s:%d", message.c_str(), file.c_str(), line); - BfpSystem_FatalError(failMsg.c_str(), "FATAL ERROR"); + char* failMsg = new char[message.length() + file.length() + 64]; + sprintf(failMsg, "%s in %s:%d", message.c_str(), file.c_str(), line); + BfpSystem_FatalError(failMsg, "FATAL ERROR"); #ifndef BF_NO_BFAPP if (gBFApp != NULL) @@ -906,6 +912,7 @@ static void __cdecl AbortHandler(int) static int64 gCPUFreq = -1; static int64 gStartCPUTick = -1; static int64 gStartQPF = -1; +static void(*sOldSIGABRTHandler)(int signal) = nullptr; static void InitCPUFreq() { @@ -918,10 +925,31 @@ static void InitCPUFreq() } } -static void(*sOldSIGABRTHandler)(int signal) = nullptr; +static void Crash_Error(const char* msg) +{ + HMODULE hMod = GetModuleHandleA(NULL); + PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; + PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)((uint8*)hMod + pDosHdr->e_lfanew); + bool isCLI = pNtHdr->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI; + + if (isCLI) + fprintf(stderr, "**** FATAL APPLICATION ERROR ****\n%s\n", msg); + else + ::MessageBoxA(NULL, msg, "FATAL ERROR", MB_ICONSTOP); + _set_purecall_handler(nullptr); + _set_invalid_parameter_handler(nullptr); + signal(SIGABRT, sOldSIGABRTHandler); + abort(); +} + +static void Crash_Error_CrashHandler(const char* msg) +{ + CrashCatcher::Get()->Crash(msg); +} BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags) { + gCrashErrorFunc = Crash_Error; InitCPUFreq(); ::_set_error_mode(_OUT_TO_STDERR); @@ -935,7 +963,9 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flag if (version != BFP_VERSION) { - BfpSystem_FatalError(StrFormat("Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version).c_str(), "BFP FATAL ERROR"); + char msg[1024]; + sprintf(msg, "Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version); + BfpSystem_FatalError(msg, "BFP FATAL ERROR"); } if ((flags & BfpSystemInitFlag_InstallCrashCatcher) != 0) @@ -953,13 +983,17 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flag sOldSIGABRTHandler = signal(SIGABRT, &AbortHandler); if (sOldSIGABRTHandler == SIG_ERR) sOldSIGABRTHandler = nullptr; - - CrashCatcher::Get()->Init(); - if ((flags & BfpSystemInitFlag_SilentCrash) != 0) - CrashCatcher::Get()->SetCrashReportKind(BfpCrashReportKind_None); } } +BFP_EXPORT void BFP_CALLTYPE BfpSystem_InitCrashCatcher(BfpSystemInitFlags flags) +{ + CrashCatcher::Get()->Init(); + if ((flags & BfpSystemInitFlag_SilentCrash) != 0) + CrashCatcher::Get()->SetCrashReportKind(BfpCrashReportKind_None); + gCrashErrorFunc = Crash_Error_CrashHandler; +} + BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) { // This isn't required on Windows, but it is on Linux @@ -993,7 +1027,10 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_Shutdown() delete gManagerTail; gManagerTail = next; } +} +BFP_EXPORT void BFP_CALLTYPE BfpSystem_ShutdownCrashCatcher() +{ if (CrashCatcher::Shutdown()) { _set_purecall_handler(nullptr); @@ -1092,9 +1129,17 @@ BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* pt BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title) { if (title != NULL) - CrashCatcher::Get()->Crash(String(title) + "\n" + String(error)); - else - CrashCatcher::Get()->Crash(error); + { + int errorLen = (int)strlen(error); + int titleLen = (int)strlen(title); + char* str = new char[errorLen + 1 + titleLen + 1]; + strcpy(str, title); + strcat(str, "\n"); + strcat(str, error); + gCrashErrorFunc(str); + } + else + gCrashErrorFunc(error); } BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) @@ -2245,9 +2290,12 @@ static LOCATEXSTATEFEATURE pfnLocateXStateFeature = NULL; typedef BOOL(WINAPI* SETXSTATEFEATURESMASK)(PCONTEXT Context, DWORD64 FeatureMask); static SETXSTATEFEATURESMASK pfnSetXStateFeaturesMask = NULL; -static uint8 ContextBuffer[4096]; +static uint8* ContextBuffer; static CONTEXT* CaptureRegistersEx(HANDLE hThread, intptr*& curPtr) { + if (ContextBuffer == NULL) + ContextBuffer = new uint8[4096]; + PCONTEXT Context; DWORD ContextSize; DWORD64 FeatureMask; diff --git a/BeefySysLib/util/String.h b/BeefySysLib/util/String.h index e93afb80..63be3b47 100644 --- a/BeefySysLib/util/String.h +++ b/BeefySysLib/util/String.h @@ -194,7 +194,7 @@ public: this->mPtr = sv.mPtr + offset; this->mLength = length; } - + StringView(const StringImpl& str); StringView(const StringImpl& str, int offset); StringView(const StringImpl& str, int offset, int length); @@ -211,7 +211,7 @@ public: this->mPtr = ptr; this->mLength = length; } - + const char& operator[](intptr idx) const { BF_ASSERT((uintptr)idx < (uintptr)this->mLength); @@ -328,9 +328,9 @@ public: bool Contains(const StringView& str) const { return IndexOf(str) != -1; - } + } - StringSplitEnumerator Split(char c); + StringSplitEnumerator Split(char c); const_iterator begin() const { @@ -340,7 +340,7 @@ public: const_iterator end() const { return mPtr + this->mLength; - } + } }; struct StringSplitEnumerator @@ -510,7 +510,7 @@ public: { StringSplitEnumerator endVal = *this; endVal.mPos = endVal.mStrLen + 1; - endVal.mMatchPos = endVal.mStrLen; + endVal.mMatchPos = endVal.mStrLen; return endVal; } }; @@ -543,7 +543,7 @@ public: char* mPtr; public: - + protected: void EnsureMutable() @@ -568,14 +568,14 @@ protected: free(this->mPtr); } - intptr CalcNewSize(intptr minSize); + intptr CalcNewSize(intptr minSize); void Realloc(intptr newSize, bool copyStr = true); - void Realloc(char* newPtr, intptr newSize); - static bool EqualsHelper(const char* a, const char* b, intptr length); - static bool EqualsIgnoreCaseHelper(const char* a, const char* b, intptr length); + void Realloc(char* newPtr, intptr newSize); + static bool EqualsHelper(const char* a, const char* b, intptr length); + static bool EqualsIgnoreCaseHelper(const char* a, const char* b, intptr length); static int CompareOrdinalIgnoreCaseHelper(const StringImpl& strA, const StringImpl& strB); static intptr CompareOrdinalIgnoreCaseHelper(const char* strA, intptr lengthA, const char* strB, intptr lengthB); - static intptr CompareOrdinalIgnoreCaseHelper(const StringImpl& strA, intptr indexA, intptr lengthA, const StringImpl& strB, intptr indexB, intptr lengthB); + static intptr CompareOrdinalIgnoreCaseHelper(const StringImpl& strA, intptr indexA, intptr lengthA, const StringImpl& strB, intptr indexB, intptr lengthB); static intptr CompareOrdinalHelper(const char* strA, intptr lengthA, const char* strB, intptr lengthB); static intptr CompareOrdinalHelper(const StringImpl& strA, intptr indexA, intptr lengthA, const StringImpl& strB, intptr indexB, intptr lengthB); @@ -613,7 +613,7 @@ protected: } -public: +public: static StringImpl MakeRef(const char* charPtr) { StringImpl str; @@ -710,7 +710,7 @@ public: this->mLength = count; } } - + ~StringImpl() { if (IsDynAlloc()) @@ -783,11 +783,11 @@ public: bool operator>(const StringImpl& strB) const { return strcmp(GetPtr(), strB.GetPtr()) > 0; - } - + } + StringImpl& operator=(const StringImpl& str) { - if (&str != this) + if (&str != this) { this->mLength = 0; Append(str.GetPtr(), str.mLength); @@ -812,14 +812,14 @@ public: { // If there's an internal buffer then we have to copy int_strsize count = (int_strsize)str.mLength; - int_strsize allocSize = count + 1; + int_strsize allocSize = count + 1; if (allocSize > GetAllocSize()) Realloc(allocSize, false); auto ptr = GetMutablePtr(); memcpy(ptr, str.GetPtr(), count + 1); - ptr[count] = 0; + ptr[count] = 0; this->mLength = count; - } + } return *this; } @@ -924,12 +924,12 @@ public: void Reserve(intptr newSize); void Append(const char* appendPtr); - void Append(const char* appendPtr, intptr length); - void Append(const StringView& str); + void Append(const char* appendPtr, intptr length); + void Append(const StringView& str); void Append(const StringImpl& str); void Append(const StringImpl& str, const StringImpl& str2); void Append(const StringImpl& str, const StringImpl& str2, const StringImpl& str3); - void Append(char c, int count = 1); + void Append(char c, int count = 1); void Release() { @@ -937,7 +937,7 @@ public: DeletePtr(); this->mLength = 0; this->mPtr = NULL; - this->mAllocSizeAndFlags = 0; + this->mAllocSizeAndFlags = 0; } void Clear() @@ -955,10 +955,10 @@ public: String Substring(intptr startIdx) const; String Substring(intptr startIdx, intptr length) const; - void Remove(intptr startIdx, intptr length); - void Remove(intptr char8Idx); - void RemoveToEnd(intptr startIdx); - void RemoveFromEnd(intptr length); + void Remove(intptr startIdx, intptr length); + void Remove(intptr char8Idx); + void RemoveToEnd(intptr startIdx); + void RemoveFromEnd(intptr length); void Insert(intptr idx, const StringImpl& addString); void Insert(intptr idx, const char* str, intptr len); void Insert(intptr idx, char c); @@ -971,14 +971,14 @@ public: } static intptr Compare(const StringImpl& strA, const StringImpl& strB, bool ignoreCase) - { + { if (ignoreCase) return CompareOrdinalIgnoreCaseHelper(strA.GetPtr(), strA.GetLength(), strB.GetPtr(), strB.GetLength()); return CompareOrdinalHelper(strA.GetPtr(), strA.GetLength(), strB.GetPtr(), strB.GetLength()); } static intptr Compare(const StringImpl& strA, intptr indexA, const StringImpl& strB, intptr indexB, intptr length, bool ignoreCase); - + bool Equals(const StringImpl& b, CompareKind comparisonType = CompareKind_Ordinal) const { return Equals(*this, b, comparisonType); @@ -1021,16 +1021,16 @@ public: bool EndsWith(char c) const { if (this->mLength == 0) - return false; + return false; return GetPtr()[this->mLength - 1] == c; } void ReplaceLargerHelper(const StringView& find, const StringView& replace); void Replace(char find, char replace); void Replace(const StringView& find, const StringView& replace); - void TrimEnd(); - void TrimStart(); - void Trim(); + void TrimEnd(); + void TrimStart(); + void Trim(); bool IsWhitespace() const; bool IsEmpty() const { @@ -1045,12 +1045,12 @@ public: bool HasMultibyteChars(); intptr IndexOf(const StringView& subStr, bool ignoreCase = false) const; intptr IndexOf(const StringView& subStr, int32 startIdx) const; - intptr IndexOf(const StringView& subStr, int64 startIdx) const; - intptr IndexOf(char c, int32 startIdx = 0) const; + intptr IndexOf(const StringView& subStr, int64 startIdx) const; + intptr IndexOf(char c, int32 startIdx = 0) const; intptr IndexOf(char c, int64 startIdx) const; - intptr LastIndexOf(char c) const; + intptr LastIndexOf(char c) const; intptr LastIndexOf(char c, intptr startCheck) const; - + StringSplitEnumerator Split(char c) { return StringSplitEnumerator(GetPtr(), mLength, c, 0x7FFFFFFF, false); @@ -1060,7 +1060,7 @@ public: { return IndexOf(c) != -1; } - + bool Contains(const StringView& str) const { return IndexOf(str) != -1; @@ -1217,6 +1217,41 @@ public: } }; +class StringSimple : public StringView +{ +public: + StringSimple() + { + + } + + StringSimple(const StringView& sv) + { + this->mPtr = new char[sv.mLength + 1]; + this->mLength = sv.mLength; + memcpy((char*)this->mPtr, sv.mPtr, this->mLength); + ((char*)this->mPtr)[this->mLength] = 0; + } + + StringSimple(const StringImpl& str) + { + this->mPtr = new char[str.mLength + 1]; + this->mLength = str.mLength; + memcpy((char*)this->mPtr, str.GetPtr(), this->mLength); + ((char*)mPtr)[this->mLength] = 0; + } + + ~StringSimple() + { + delete this->mPtr; + } + + const char* c_str() + { + return this->mPtr; + } +}; + class UTF16String : public Array { public: @@ -1227,7 +1262,7 @@ public: void Set(const wchar_t* str, int len); void Set(const wchar_t* str); const wchar_t* c_str() const; - size_t length() const; + size_t length() const; }; #define BF_SPECIALIZE_STR(size) \ diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index f0f8caa0..ddd04a3e 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -24,7 +24,7 @@ OtherLinkFlags = "" TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" -DebugCommandArguments = "-proddir=\"$(WorkspaceDir)\\..\\IDE\"" +DebugCommandArguments = "-proddir=\"$(WorkspaceDir)\\..\\BeefBuild\"" DebugWorkingDirectory = "$(WorkspaceDir)\\.." EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/Tests/Tiny/BeefProj.toml b/IDE/Tests/Tiny/BeefProj.toml new file mode 100644 index 00000000..4918219b --- /dev/null +++ b/IDE/Tests/Tiny/BeefProj.toml @@ -0,0 +1,8 @@ +FileVersion = 1 + +[Project] +Name = "Tiny" +StartupObject = "Tiny.Program" + +[Configs.Release.Win64] +CLibType = "SystemMSVCRT" diff --git a/IDE/Tests/Tiny/BeefSpace.toml b/IDE/Tests/Tiny/BeefSpace.toml new file mode 100644 index 00000000..9ec4296a --- /dev/null +++ b/IDE/Tests/Tiny/BeefSpace.toml @@ -0,0 +1,26 @@ +FileVersion = 1 +Projects = {Tiny = {Path = "."}} +Unlocked = ["corlib"] + +[Workspace] +StartupProject = "Tiny" + +[Configs.Debug.Win64] +AllocType = "CRT" +RuntimeKind = "Reduced" +ReflectKind = "Minimal" +RuntimeChecks = false +EmitDynamicCastCheck = false +EnableObjectDebugFlags = false +EmitObjectAccessCheck = false +EnableRealtimeLeakCheck = false +AllowHotSwapping = false +IntermediateType = "ObjectAndIRCode" + +[Configs.Debug.Win32] +RuntimeKind = "Reduced" +ReflectKind = "Minimal" + +[Configs.Release.Win64] +RuntimeKind = "Reduced" +ReflectKind = "Minimal" diff --git a/IDE/Tests/Tiny/src/Program.bf b/IDE/Tests/Tiny/src/Program.bf new file mode 100644 index 00000000..be19d3b3 --- /dev/null +++ b/IDE/Tests/Tiny/src/Program.bf @@ -0,0 +1,13 @@ +using System; +using System.Diagnostics; + +namespace Tiny; + +class Program +{ + public static int Main() + { + Console.WriteLine("Hello, World!"); + return 0; + } +} \ No newline at end of file diff --git a/IDE/mintest/minlib/src/System/Attribute.bf b/IDE/mintest/minlib/src/System/Attribute.bf index d05dc12e..885264c2 100644 --- a/IDE/mintest/minlib/src/System/Attribute.bf +++ b/IDE/mintest/minlib/src/System/Attribute.bf @@ -110,13 +110,13 @@ namespace System [AttributeUsage(.Method | .Constructor | .Invocation)] public struct InlineAttribute : Attribute { - + } [AttributeUsage(.Invocation)] public struct UnboundAttribute : Attribute { - + } [AttributeUsage(.Class | .Struct | .Interface | .Method | .Constructor)] @@ -136,13 +136,13 @@ namespace System [AttributeUsage(.MemberAccess | .Alloc)] public struct FriendAttribute : Attribute { - + } [AttributeUsage(.MemberAccess)] public struct NoExtensionAttribute : Attribute { - + } [AttributeUsage(.Block)] @@ -161,13 +161,13 @@ namespace System [AttributeUsage(.Method | .Class | .Struct | .Enum)] public struct OptimizeAttribute : Attribute { - + } [AttributeUsage(.Method | .Class | .Struct | .Enum)] public struct UseLLVMAttribute : Attribute { - + } [AttributeUsage(.Method /*2*/ | .StaticField)] @@ -344,7 +344,7 @@ namespace System [AttributeUsage(.Enum)] public struct AllowDuplicatesAttribute : Attribute { - + } [AttributeUsage(.Class | .Struct)] @@ -409,7 +409,7 @@ namespace System public struct ExportAttribute : Attribute { - + } [AttributeUsage(.StaticField | .Field, .NotInherited)] @@ -420,6 +420,12 @@ namespace System } } + [AttributeUsage(.MemberAccess)] + public struct NoStaticCtorAttribute : Attribute + { + + } + /// The [Checked] attribute is used to mark a method or a method invocation as being "checked", meaning /// that the method applies extra runtime checks such as bounds checking or other parameter or state validation. [AttributeUsage(.Invocation | .Method | .Property)] diff --git a/IDE/mintest/minlib/src/System/Internal.bf b/IDE/mintest/minlib/src/System/Internal.bf index 443c7a4f..22ffbb9e 100644 --- a/IDE/mintest/minlib/src/System/Internal.bf +++ b/IDE/mintest/minlib/src/System/Internal.bf @@ -92,8 +92,15 @@ namespace System [CallingConvention(.Cdecl)] public static extern void Dbg_RawFree(void* ptr); + [CallingConvention(.Cdecl)] + static extern void Shutdown_Internal(); + [CallingConvention(.Cdecl), AlwaysInclude] - static extern void Shutdown(); + static void Shutdown() + { + Shutdown_Internal(); + } + [CallingConvention(.Cdecl)] static extern void Test_Init(char8* testData); [CallingConvention(.Cdecl)] diff --git a/IDE/mintest/minlib/src/System/Object.bf b/IDE/mintest/minlib/src/System/Object.bf index 405b4b93..f2a47c3f 100644 --- a/IDE/mintest/minlib/src/System/Object.bf +++ b/IDE/mintest/minlib/src/System/Object.bf @@ -48,63 +48,122 @@ namespace System class Object : IHashable { -#if BF_ENABLE_OBJECT_DEBUG_FLAGS - int mClassVData; - int mDbgAllocInfo; -#else - ClassVData* mClassVData; -#endif - - public virtual ~this() - { + #if BF_ENABLE_OBJECT_DEBUG_FLAGS + int mClassVData; + int mDbgAllocInfo; +#else + ClassVData* mClassVData; +#endif + + public virtual ~this() + { #if BF_ENABLE_OBJECT_DEBUG_FLAGS mClassVData = ((mClassVData & ~0x08) | 0x80); -#endif - } +#endif + } - int IHashable.GetHashCode() - { - return (int)(void*)this; - } - - public Type GetType() - { - Type type; #if BF_ENABLE_OBJECT_DEBUG_FLAGS - ClassVData* maskedVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); - type = maskedVData.mType; -#else - type = mClassVData.mType; -#endif - if ((type.[Friend]mTypeFlags & TypeFlags.Boxed) != 0) - { - //int32 underlyingType = (int32)((TypeInstance)type).mUnderlyingType; - type = Type.[Friend]GetType(((TypeInstance)type).[Friend]mUnderlyingType); - } + [NoShow] + int32 GetFlags() + { + return (int32)mClassVData & 0xFF; + } + + [DisableObjectAccessChecks, NoShow] + public bool IsDeleted() + { + return (int32)mClassVData & 0x80 != 0; + } +#else + [SkipCall] + public bool IsDeleted() + { + return false; + } +#endif + extern Type Comptime_GetType(); + + public Type GetType() + { + if (Compiler.IsComptime) + return Comptime_GetType(); + + ClassVData* classVData; +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + Type type = Type.[Friend]GetType_((.)(classVData.mType2)); +#else + Type type = Type.[Friend]GetType_((.)(classVData.mType >> 32)); +#endif return type; } + TypeId GetTypeId() + { + ClassVData* classVData; +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + return (.)classVData.mType2; +#else + return (.)(classVData.mType >> 32); +#endif + } + [NoShow] Type RawGetType() { - Type type; + if (Compiler.IsComptime) + return Comptime_GetType(); + + ClassVData* classVData; #if BF_ENABLE_OBJECT_DEBUG_FLAGS - ClassVData* maskedVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); - type = maskedVData.mType; -#else - type = mClassVData.mType; -#endif - return type; + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + Type type = Type.[Friend]GetType_((.)(classVData.mType)); +#else + Type type = Type.[Friend]GetType_((.)(classVData.mType & 0xFFFFFFFF)); +#endif + return type; } + TypeId RawGetTypeId() + { + ClassVData* classVData; +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + classVData = (ClassVData*)(void*)(mClassVData & ~(int)0xFF); +#else + classVData = mClassVData; +#endif + +#if BF_32_BIT + return (.)classVData.mType; +#else + return (.)(classVData.mType & 0xFFFFFFFF); +#endif + } + #if BF_DYNAMIC_CAST_CHECK || BF_ENABLE_REALTIME_LEAK_CHECK [NoShow] - public virtual Object DynamicCastToTypeId(int32 typeId) - { - if (typeId == (int32)RawGetType().[Friend]mTypeId) - return this; - return null; - } + public virtual Object DynamicCastToTypeId(int32 typeId) + { + if (typeId == (.)RawGetTypeId()) + return this; + return null; + } [NoShow] public virtual Object DynamicCastToInterface(int32 typeId) @@ -112,13 +171,18 @@ namespace System return null; } #endif - + + int IHashable.GetHashCode() + { + return (int)Internal.UnsafeCastToPtr(this); + } + public virtual void ToString(String strBuffer) { - //strBuffer.Set(stack string(GetType().mName)); - RawGetType().GetName(strBuffer); + strBuffer.Append("Type#"); + GetTypeId().ToString(strBuffer); } - + /*public virtual int GetHashCode() { return (int)(intptr)(void*)this; @@ -138,12 +202,12 @@ namespace System obj.ToString(strBuffer); } } - + interface IResult { T GetBaseResult(); } - + struct ValueType { public static extern bool Equals(T val1, T val2); @@ -197,7 +261,7 @@ namespace System { return CSize; } - } + } public explicit static operator T[CSize] (Self val) { @@ -226,11 +290,11 @@ namespace System struct Void : void { } - + struct Boolean : bool - { + { } - + struct Char8 : char8 { public bool IsWhiteSpace @@ -248,7 +312,7 @@ namespace System struct Char16 : char16 { - + } struct Char32 : char32 @@ -258,15 +322,15 @@ namespace System get; } } - + struct Int8 : int8 - { + { } - + struct UInt8 : uint8 - { + { } - + struct Int16 : int16, IOpComparable, IIsNaN { public static int operator<=>(Int16 a, Int16 b) @@ -283,11 +347,11 @@ namespace System } } } - + struct UInt16 : uint16 - { + { } - + struct UInt32 : uint32, IHashable, IOpComparable, IIsNaN, IOpNegatable { public const int32 MaxValue = 0x7FFFFFFF; @@ -307,7 +371,7 @@ namespace System public this() { - + } bool IIsNaN.IsNaN @@ -324,12 +388,12 @@ namespace System return (.)this; } } - + struct Int64 : int64 { public const int64 MaxValue = 0x7FFFFFFFFFFFFFFFL; public const int64 MinValue = -0x8000000000000000L; - + public override void ToString(String strBuffer) { // Dumb, make better. @@ -344,11 +408,11 @@ namespace System } if (charIdx == 14) strChars[charIdx--] = '0'; - char8* charPtr = &strChars[charIdx + 1]; + char8* charPtr = &strChars[charIdx + 1]; strBuffer.Append(scope:: String(charPtr)); } } - + struct UInt64 : uint64 { } @@ -405,7 +469,7 @@ namespace System } struct UInt : uint, IOpComparable, IIsNaN - { + { public static int operator<=>(UInt a, UInt b) { return (uint)a <=> (uint)b; @@ -469,11 +533,11 @@ namespace System } if (charIdx == 14) strChars[charIdx--] = '0'; - char8* charPtr = &strChars[charIdx + 1]; + char8* charPtr = &strChars[charIdx + 1]; strBuffer.Append(scope:: String(charPtr)); } } - + struct Enum { public static Result Parse(String str) where T : Enum @@ -528,7 +592,7 @@ namespace System { public int64 mMethodId; public DeferredCall* mNext; - + public void Cancel() mut { mMethodId = 0; diff --git a/IDE/mintest/minlib/src/System/Type.bf b/IDE/mintest/minlib/src/System/Type.bf index bd6df73e..2a9fb9dd 100644 --- a/IDE/mintest/minlib/src/System/Type.bf +++ b/IDE/mintest/minlib/src/System/Type.bf @@ -7,7 +7,10 @@ namespace System { struct ClassVData { - public Type mType; + public int mType; +#if BF_32_BIT + public int mType2; +#endif // The rest of this structured is generated by the compiler, // including the vtable and interface slots } @@ -757,6 +760,7 @@ namespace System.Reflection public int32 mCustomAttributesIdx; } + [CRepr, AlwaysInclude] public struct InterfaceData { public TypeId mInterfaceType; diff --git a/IDE/mintest/src/main.bf b/IDE/mintest/src/main.bf index 7156c5e5..62931831 100644 --- a/IDE/mintest/src/main.bf +++ b/IDE/mintest/src/main.bf @@ -46,8 +46,8 @@ namespace Hey.Dude.Bro - [Import(@"C:\Beef\BeefTools\TestDLL\x64\Debug\TestDLL.dll"), LinkName("Test2")] - public static extern void Test2(int32 a, int32 b, int32 c, int32 d, function Color(int32 a, int32 b) func); + //[Import(@"C:\Beef\BeefTools\TestDLL\x64\Debug\TestDLL.dll"), LinkName("Test2")] + //public static extern void Test2(int32 a, int32 b, int32 c, int32 d, function Color(int32 a, int32 b) func); public static Color GetColor(int32 a, int32 b) { @@ -61,7 +61,9 @@ namespace Hey.Dude.Bro public static int Main(String[] args) { - Test2(1, 2, 3, 4, => GetColor); + Debug.WriteLine("Hey!"); + + //Test2(1, 2, 3, 4, => GetColor); //Blurg.Hey(); return 1; diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index 0c67fbbf..6659e1b2 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -763,7 +763,10 @@ namespace IDE } public static void GetRtLibNames(Workspace.PlatformType platformType, Workspace.Options workspaceOptions, Project.Options options, bool dynName, String outRt, String outDbg, String outAlloc) - { + { + if (workspaceOptions.mRuntimeKind == .Disabled) + return; + if ((platformType == .Linux) || (platformType == .macOS) || (platformType == .iOS)) { if (options.mBuildOptions.mBeefLibType == .DynamicDebug) @@ -1059,10 +1062,13 @@ namespace IDE return false; }*/ - switch (options.mBuildOptions.mCLibType) + var clibType = options.mBuildOptions.mCLibType; + if (workspaceOptions.mRuntimeKind == .Disabled) + clibType = .None; + switch (clibType) { case .None: - linkLine.Append("-nodefaultlib "); + linkLine.Append("-nodefaultlib chkstk.obj "); case .Dynamic: //linkLine.Append((workspaceOptions.mMachineType == .x86) ? "-defaultlib:msvcprt " : "-defaultlib:msvcrt "); linkLine.Append("-defaultlib:msvcrt "); diff --git a/IDE/src/BuildOptions.bf b/IDE/src/BuildOptions.bf index b600af2d..23681848 100644 --- a/IDE/src/BuildOptions.bf +++ b/IDE/src/BuildOptions.bf @@ -5,6 +5,7 @@ namespace IDE { class BuildOptions { + [Reflect(.All)] public enum LTOType { case None; @@ -18,6 +19,7 @@ namespace IDE } } + [Reflect(.All)] public enum EmitDebugInfo { No, @@ -25,6 +27,7 @@ namespace IDE LinesOnly, } + [Reflect(.All)] public enum SIMDSetting { None, @@ -38,6 +41,7 @@ namespace IDE AVX2, } + [Reflect] public enum BfOptimizationLevel { case O0; @@ -53,6 +57,7 @@ namespace IDE } } + [Reflect] public enum RelocType { NotSet, @@ -64,6 +69,7 @@ namespace IDE ROPI_RWPI } + [Reflect] public enum PICLevel { NotSet, @@ -72,6 +78,7 @@ namespace IDE Big } + [Reflect] public enum AlwaysIncludeKind { NotSet, diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index 2a5bfed5..919cfa4f 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -739,9 +739,14 @@ namespace IDE.Compiler SetOpt(options.mAllowHotSwapping, .EnableHotSwapping); #endif + var allocType = options.mAllocType; + + if ((options.mRuntimeKind == .Disabled) && (allocType == .Debug)) + allocType = .CRT; + String mallocLinkName; String freeLinkName; - switch (options.mAllocType) + switch (allocType) { case .CRT: mallocLinkName = "malloc"; diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index 56a6f761..173f48c0 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -366,6 +366,9 @@ namespace IDE.Debugger [CallingConvention(.Stdcall),CLink] static extern char8* Debugger_GetModulesInfo(); + [CallingConvention(.Stdcall),CLink] + static extern char8* Debugger_GetModuleInfo(char8* moduleName); + [CallingConvention(.Stdcall),CLink] static extern bool Debugger_HasPendingDebugLoads(); @@ -1194,6 +1197,11 @@ namespace IDE.Debugger modulesInfo.Append(Debugger_GetModulesInfo()); } + public void GetModuleInfo(StringView moduleName, String moduleInfo) + { + moduleInfo.Append(Debugger_GetModuleInfo(moduleName.ToScopeCStr!())); + } + public int32 LoadDebugInfoForModule(String moduleName) { return Debugger_LoadDebugInfoForModule(moduleName); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 57dc3560..9e8674a4 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -8488,6 +8488,13 @@ namespace IDE macroList.Add("BF_LARGE_COLLECTIONS"); } + if (workspaceOptions.mRuntimeKind == .Disabled) + macroList.Add("BF_RUNTIME_DISABLE"); + if ((workspaceOptions.mRuntimeKind == .Reduced) || (workspaceOptions.mRuntimeKind == .Disabled)) + macroList.Add("BF_RUNTIME_REDUCED"); + if (workspaceOptions.mReflectKind == .Minimal) + macroList.Add("BF_REFLECT_MINIMAL"); + // Only supported on Windows at the moment bool hasLeakCheck = false; if (workspaceOptions.LeakCheckingEnabled) diff --git a/IDE/src/Workspace.bf b/IDE/src/Workspace.bf index 349665a5..cdfaae08 100644 --- a/IDE/src/Workspace.bf +++ b/IDE/src/Workspace.bf @@ -94,6 +94,12 @@ namespace IDE BitcodeAndIRCode, } + public enum ReflectKind + { + Normal, + Minimal + } + public enum PlatformType { case Unknown; @@ -263,6 +269,13 @@ namespace IDE Custom } + public enum RuntimeKind + { + Default, + Reduced, + Disabled + } + public class BeefGlobalOptions { [Reflect] @@ -305,6 +318,10 @@ namespace IDE [Reflect] public bool mLargeCollections; [Reflect] + public RuntimeKind mRuntimeKind; + [Reflect] + public ReflectKind mReflectKind; + [Reflect] public AllocType mAllocType = .CRT; [Reflect] public String mAllocMalloc = new String() ~ delete _; @@ -352,7 +369,7 @@ namespace IDE get { #if BF_PLATFORM_WINDOWS - return mEnableRealtimeLeakCheck && mEnableObjectDebugFlags && (mAllocType == .Debug); + return mEnableRealtimeLeakCheck && mEnableObjectDebugFlags && (mAllocType == .Debug) && (mRuntimeKind != .Disabled); #else return false; #endif @@ -376,6 +393,8 @@ namespace IDE mNoOmitFramePointers = prev.mNoOmitFramePointers; mLargeStrings = prev.mLargeStrings; mLargeCollections = prev.mLargeCollections; + mRuntimeKind = prev.mRuntimeKind; + mReflectKind = prev.mReflectKind; mAllocType = prev.mAllocType; mAllocMalloc.Set(prev.mAllocMalloc); mAllocFree.Set(prev.mAllocFree); @@ -813,6 +832,8 @@ namespace IDE data.ConditionalAdd("NoOmitFramePointers", options.mNoOmitFramePointers, false); data.ConditionalAdd("LargeStrings", options.mLargeStrings, false); data.ConditionalAdd("LargeCollections", options.mLargeCollections, false); + data.ConditionalAdd("RuntimeKind", options.mRuntimeKind); + data.ConditionalAdd("ReflectKind", options.mReflectKind); data.ConditionalAdd("InitLocalVariables", options.mInitLocalVariables, false); data.ConditionalAdd("RuntimeChecks", options.mRuntimeChecks, !isRelease); data.ConditionalAdd("EmitDynamicCastCheck", options.mEmitDynamicCastCheck, !isRelease); @@ -1004,6 +1025,8 @@ namespace IDE options.mNoOmitFramePointers = false; options.mLargeStrings = false; options.mLargeCollections = false; + options.mRuntimeKind = .Default; + options.mReflectKind = .Normal; options.mInitLocalVariables = false; options.mRuntimeChecks = !isRelease; options.mEmitDynamicCastCheck = !isRelease; @@ -1113,6 +1136,8 @@ namespace IDE options.mNoOmitFramePointers = data.GetBool("NoOmitFramePointers", false); options.mLargeStrings = data.GetBool("LargeStrings", false); options.mLargeCollections = data.GetBool("LargeCollections", false); + options.mRuntimeKind = data.GetEnum("RuntimeKind"); + options.mReflectKind = data.GetEnum("ReflectKind"); options.mInitLocalVariables = data.GetBool("InitLocalVariables", false); options.mRuntimeChecks = data.GetBool("RuntimeChecks", !isRelease); options.mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck", !isRelease); diff --git a/IDE/src/ui/ModulePanel.bf b/IDE/src/ui/ModulePanel.bf index 5f81f3a2..432f2988 100644 --- a/IDE/src/ui/ModulePanel.bf +++ b/IDE/src/ui/ModulePanel.bf @@ -158,6 +158,20 @@ namespace IDE.ui } }); }); + + anItem = menu.AddItem("Copy Info to Clipboard"); + anItem.mOnMenuItemSelected.Add(new (item) => + { + String moduleInfo = scope .(); + listView.GetRoot().WithSelectedItems(scope (item) => + { + if (!moduleInfo.IsEmpty) + moduleInfo.Append("\n"); + gApp.mDebugger.GetModuleInfo(item.GetSubItem(1).Label, moduleInfo); + }); + gApp.SetClipboardText(moduleInfo); + }); + MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu); menuWidget.Init(relWidget, x, y); } diff --git a/IDE/src/ui/WorkspaceProperties.bf b/IDE/src/ui/WorkspaceProperties.bf index b31404c0..639dc1b9 100644 --- a/IDE/src/ui/WorkspaceProperties.bf +++ b/IDE/src/ui/WorkspaceProperties.bf @@ -797,6 +797,8 @@ namespace IDE.ui AddPropertiesItem(category, "No Omit Frame Pointers", "mNoOmitFramePointers"); AddPropertiesItem(category, "Large Strings", "mLargeStrings"); AddPropertiesItem(category, "Large Collections", "mLargeCollections"); + AddPropertiesItem(category, "Runtime", "mRuntimeKind"); + AddPropertiesItem(category, "Reflection", "mReflectKind"); category.Open(true, true); (category, propEntry) = AddPropertiesItem(root, "Debug"); diff --git a/IDEHelper/COFF.cpp b/IDEHelper/COFF.cpp index 647f1a2c..6c01ad34 100644 --- a/IDEHelper/COFF.cpp +++ b/IDEHelper/COFF.cpp @@ -509,7 +509,7 @@ addr_target COFF::GetSectionAddr(uint16 section, uint32 offset) return hiBase + offset; } - int rva = mSectionRVAs[section - 1]; + int rva = mSectionHeaders[section - 1].mVirtualAddress; if (rva == 0) return ADDR_FLAG_ABS + offset; @@ -5178,6 +5178,7 @@ bool COFF::CvParseDBI(int wantAge) contribEntry->mLength = curSize; contribEntry->mDbgModule = this; contribEntry->mCompileUnitId = contrib.mModule; + contribEntry->mSection = contrib.mSection; mDebugTarget->mContribMap.Insert(contribEntry); } } @@ -5288,7 +5289,7 @@ bool COFF::CvParseDBI(int wantAge) void COFF::ParseSectionHeader(int sectionIdx) { - bool fakeRVAS = mSectionRVAs.empty(); + bool fakeRVAS = mSectionHeaders.empty(); int sectionSize = 0; uint8* sectionData = CvReadStream(sectionIdx, §ionSize); @@ -5300,12 +5301,15 @@ void COFF::ParseSectionHeader(int sectionIdx) auto& sectionHeader = GET(PESectionHeader); if (fakeRVAS) { - mSectionRVAs.push_back(sectionHeader.mVirtualAddress); + mSectionHeaders.push_back(sectionHeader); } } if (fakeRVAS) - mSectionRVAs.push_back(0); + { + PESectionHeader sectionHeader = { 0 }; + mSectionHeaders.push_back(sectionHeader); + } delete sectionData; } diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index ac02b431..f15c605c 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -1220,7 +1220,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) Array vdataTypeList; HashSet usedModuleSet; - HashSet reflectTypeSet; + HashSet reflectSkipTypeSet; HashSet reflectFieldTypeSet; vdataHashCtx.MixinStr(project->mStartupObject); @@ -1398,20 +1398,49 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) bool madeBfTypeData = false; auto typeDefType = mContext->mBfTypeType; - bool needsTypeList = bfModule->IsMethodImplementedAndReified(typeDefType, "GetType"); + bool needsFullTypeList = bfModule->IsMethodImplementedAndReified(typeDefType, "GetType"); + bool needsTypeList = needsFullTypeList || bfModule->IsMethodImplementedAndReified(typeDefType, "GetType_"); bool needsObjectTypeData = needsTypeList || bfModule->IsMethodImplementedAndReified(vdataContext->mBfObjectType, "RawGetType") || bfModule->IsMethodImplementedAndReified(vdataContext->mBfObjectType, "GetType"); bool needsTypeNames = bfModule->IsMethodImplementedAndReified(typeDefType, "GetName") || bfModule->IsMethodImplementedAndReified(typeDefType, "GetFullName"); bool needsStringLiteralList = (mOptions.mAllowHotSwapping) || (bfModule->IsMethodImplementedAndReified(stringType, "Intern")) || (bfModule->IsMethodImplementedAndReified(stringViewType, "Intern")); - Dictionary usedStringIdMap; + BfCreateTypeDataContext createTypeDataCtx; - reflectTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectTypeInstanceTypeDef)); - reflectTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectSpecializedGenericType)); - reflectTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectUnspecializedGenericType)); - reflectTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectArrayType)); - reflectTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectGenericParamType)); + if (!needsTypeList) + { + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mTypeTypeDef)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectTypeInstanceTypeDef)); + } + if (!needsFullTypeList) + { + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectSpecializedGenericType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectUnspecializedGenericType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectConstExprType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectArrayType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectGenericParamType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectPointerType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectSizedArrayType)); + reflectSkipTypeSet.Add(vdataContext->mUnreifiedModule->ResolveTypeDef(mReflectRefType)); + } + + HashSet boxeeSet; + for (auto type : vdataTypeList) + { + auto typeInst = type->ToTypeInstance(); + + if ((!type->IsReified()) || (type->IsUnspecializedType())) + continue; + + if (type->IsBoxed()) + boxeeSet.Add(typeInst->GetUnderlyingType()); + } + + int usedTypeCount = 0; + HashSet vDataTypeSet; SmallVector typeDataVector; + Array usedTypeDataVector; + for (auto type : vdataTypeList) { if (type->IsTypeAlias()) @@ -1425,9 +1454,12 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) if ((typeInst != NULL) && (!typeInst->IsReified()) && (!typeInst->IsUnspecializedType())) continue; - bool needsTypeData = (needsTypeList) || ((type->IsObject()) && (needsObjectTypeData)); + bool needsTypeData = (needsFullTypeList) || ((type->IsObject()) && (needsObjectTypeData)); bool needsVData = (type->IsObject()) && (typeInst->HasBeenInstantiated()); + if ((needsObjectTypeData) && (boxeeSet.Contains(typeInst))) + needsTypeData = true; + bool forceReflectFields = false; if (bfModule->mProject->mReferencedTypeData.Contains(type)) @@ -1437,8 +1469,16 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) forceReflectFields = true; } - BfIRValue typeVariable; + if (reflectSkipTypeSet.Contains(type)) + { + if (!bfModule->mProject->mReferencedTypeData.Contains(type)) + { + needsTypeData = false; + needsVData = false; + } + } + BfIRValue typeVariable; if ((needsTypeData) || (needsVData)) { if (reflectFieldTypeSet.Contains(type)) @@ -1446,14 +1486,25 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) needsTypeData = true; forceReflectFields = true; } - else if (reflectTypeSet.Contains(type)) + /*else if (reflectTypeSet.Contains(type)) { needsTypeData = true; needsVData = true; - } + }*/ - typeVariable = bfModule->CreateTypeData(type, usedStringIdMap, forceReflectFields, needsTypeData, needsTypeNames, needsVData); + if (needsVData) + vDataTypeSet.Add(type); + + typeVariable = bfModule->CreateTypeData(type, createTypeDataCtx, forceReflectFields, needsTypeData, needsTypeNames, needsVData); + if (typeVariable) + usedTypeDataVector.Add(type); } + else if ((type->IsInterface()) && (typeInst->mSlotNum >= 0)) + { + bfModule->CreateSlotOfs(typeInst); + } + + usedTypeCount++; type->mDirty = false; if (needsTypeList) @@ -1573,13 +1624,13 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) BfMangler::MangleStaticFieldName(stringsVariableName, GetMangleKind(), stringType->ToTypeInstance(), "sIdStringLiterals", stringPtrType); Array stringList; - stringList.Resize(usedStringIdMap.size()); - for (auto& kv : usedStringIdMap) + stringList.Resize(createTypeDataCtx.mUsedStringIdMap.size()); + for (auto& kv : createTypeDataCtx.mUsedStringIdMap) { stringList[kv.mValue] = bfModule->mStringObjectPool[kv.mKey]; } - BfIRType stringArrayType = bfModule->mBfIRBuilder->GetSizedArrayType(stringPtrIRType, (int)usedStringIdMap.size()); + BfIRType stringArrayType = bfModule->mBfIRBuilder->GetSizedArrayType(stringPtrIRType, (int)createTypeDataCtx.mUsedStringIdMap.size()); auto stringArray = bfModule->mBfIRBuilder->CreateConstAgg_Value(stringArrayType, stringList); auto stringArrayVar = bfModule->mBfIRBuilder->CreateGlobalVariable(stringArrayType, true, BfIRLinkageType_External, stringArray, stringsVariableName); @@ -3994,10 +4045,10 @@ void BfCompiler::VisitSourceExteriorNodes() if (auto genericTypeRef = BfNodeDynCast(usingDirective->mTypeRef)) { - mContext->mScratchModule->ResolveTypeRefAllowUnboundGenerics(usingDirective->mTypeRef, BfPopulateType_Identity); + mContext->mScratchModule->ResolveTypeRefAllowUnboundGenerics(usingDirective->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_NoReify); } else - mContext->mScratchModule->ResolveTypeRef(usingDirective->mTypeRef, BfPopulateType_Identity); + mContext->mScratchModule->ResolveTypeRef(usingDirective->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_NoReify); if ((mResolvePassData != NULL) && (mResolvePassData->mAutoComplete != NULL)) mResolvePassData->mAutoComplete->CheckTypeRef(usingDirective->mTypeRef, false, false); @@ -5608,12 +5659,19 @@ void BfCompiler::ClearBuildCache() } } +int BfCompiler::GetVDataPrefixDataCount() +{ + return (mSystem->mPtrSize == 4) ? 2 : 1; +} + int BfCompiler::GetDynCastVDataCount() { int dynElements = 1 + mMaxInterfaceSlots; return ((dynElements * 4) + mSystem->mPtrSize - 1) / mSystem->mPtrSize; } + + bool BfCompiler::IsAutocomplete() { return (mResolvePassData != NULL) && (mResolvePassData->mAutoComplete != NULL); @@ -7177,6 +7235,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mActionTypeDef = _GetRequiredType("System.Action"); mEnumTypeDef = _GetRequiredType("System.Enum"); mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute"); + mNoStaticCtorAttributeTypeDef = _GetRequiredType("System.NoStaticCtorAttribute"); mComptimeAttributeTypeDef = _GetRequiredType("System.ComptimeAttribute"); mConstEvalAttributeTypeDef = _GetRequiredType("System.ConstEvalAttribute"); mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute"); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 86a38631..ff45f079 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -442,6 +442,7 @@ public: BfTypeDef* mDisableChecksAttributeTypeDef; BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; BfTypeDef* mFriendAttributeTypeDef; + BfTypeDef* mNoStaticCtorAttributeTypeDef; BfTypeDef* mComptimeAttributeTypeDef; BfTypeDef* mConstEvalAttributeTypeDef; BfTypeDef* mNoExtensionAttributeTypeDef; @@ -501,6 +502,7 @@ public: void MarkStringPool(BfIRConstHolder* constHolder, BfIRValue irValue); void ClearUnusedStringPoolEntries(); void ClearBuildCache(); + int GetVDataPrefixDataCount(); int GetDynCastVDataCount(); bool IsAutocomplete(); bool IsDataResolvePass(); diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 86b50fb4..bbfa4f9a 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -420,55 +420,74 @@ bool BfContext::ProcessWorkList(bool onlyReifiedTypes, bool onlyReifiedMethods) didWork = true; } - for (int workIdx = 0; workIdx < (int)mPopulateTypeWorkList.size(); workIdx++) + for (int populatePass = 0; populatePass < 2; populatePass++) { - //BP_ZONE("PWL_PopulateType"); - if (IsCancellingAndYield()) - break; - - auto workItemRef = mPopulateTypeWorkList[workIdx]; - if (workItemRef == NULL) + for (int workIdx = 0; workIdx < (int)mPopulateTypeWorkList.size(); workIdx++) { - workIdx = mPopulateTypeWorkList.RemoveAt(workIdx); - continue; - } + //BP_ZONE("PWL_PopulateType"); + if (IsCancellingAndYield()) + break; + if (!mMidCompileWorkList.IsEmpty()) + { + // Let these mid-compiles occur as soon as possible + break; + } - BfType* type = workItemRef->mType; - bool rebuildType = workItemRef->mRebuildType; + auto workItemRef = mPopulateTypeWorkList[workIdx]; + if (workItemRef == NULL) + { + workIdx = mPopulateTypeWorkList.RemoveAt(workIdx); + continue; + } - if ((onlyReifiedTypes) && (!type->IsReified())) - { - continue; - } + BfType* type = workItemRef->mType; + bool rebuildType = workItemRef->mRebuildType; - auto typeInst = type->ToTypeInstance(); - if ((typeInst != NULL) && (resolveParser != NULL)) - { - if (!typeInst->mTypeDef->GetLatest()->HasSource(resolveParser)) + if ((onlyReifiedTypes) && (!type->IsReified())) { continue; } + + // We want to resolve type aliases first, allowing possible mMidCompileWorkList entries + int wantPass = type->IsTypeAlias() ? 0 : 1; + if (populatePass != wantPass) + continue; + + auto typeInst = type->ToTypeInstance(); + if ((typeInst != NULL) && (resolveParser != NULL)) + { + if (!typeInst->mTypeDef->GetLatest()->HasSource(resolveParser)) + { + continue; + } + } + + workIdx = mPopulateTypeWorkList.RemoveAt(workIdx); + + if (rebuildType) + RebuildType(type); + + BF_ASSERT(this == type->mContext); + auto useModule = type->GetModule(); + if (useModule == NULL) + { + if (mCompiler->mOptions.mCompileOnDemandKind == BfCompileOnDemandKind_AlwaysInclude) + useModule = mScratchModule; + else + useModule = mUnreifiedModule; + } + if (!type->IsDeleting()) + useModule->PopulateType(type, BfPopulateType_Full); + mCompiler->mStats.mQueuedTypesProcessed++; + mCompiler->UpdateCompletion(); + didWork = true; } + } - workIdx = mPopulateTypeWorkList.RemoveAt(workIdx); - - if (rebuildType) - RebuildType(type); - - BF_ASSERT(this == type->mContext); - auto useModule = type->GetModule(); - if (useModule == NULL) - { - if (mCompiler->mOptions.mCompileOnDemandKind == BfCompileOnDemandKind_AlwaysInclude) - useModule = mScratchModule; - else - useModule = mUnreifiedModule; - } - if (!type->IsDeleting()) - useModule->PopulateType(type, BfPopulateType_Full); - mCompiler->mStats.mQueuedTypesProcessed++; - mCompiler->UpdateCompletion(); - didWork = true; + if ((!mMidCompileWorkList.IsEmpty()) && (didWork)) + { + // Let the mid-compile occur ASAP + continue; } for (int workIdx = 0; workIdx < (int)mTypeRefVerifyWorkList.size(); workIdx++) @@ -1984,6 +2003,7 @@ void BfContext::DeleteType(BfType* type, bool deferDepRebuilds) } else if (dependentTypeInst != NULL) { + mGhostDependencies.Add(type); // This keeps us from crashing from accessing deleted types on subsequent compiles mFailTypes.TryAdd(dependentTypeInst, BfFailKind_Normal); } @@ -2396,6 +2416,38 @@ void BfContext::UpdateRevisedTypes() } } + // Handle these "mid-compiles" now so we handle them as early-stage + BfParser* resolveParser = NULL; + if ((mCompiler->mResolvePassData != NULL) && (!mCompiler->mResolvePassData->mParsers.IsEmpty())) + resolveParser = mCompiler->mResolvePassData->mParsers[0]; + for (int workIdx = 0; workIdx < (int)mMidCompileWorkList.size(); workIdx++) + { + auto workItemRef = mMidCompileWorkList[workIdx]; + if (workItemRef == NULL) + { + workIdx = mMidCompileWorkList.RemoveAt(workIdx); + continue; + } + + BfType* type = workItemRef->mType; + String reason = workItemRef->mReason; + + auto typeInst = type->ToTypeInstance(); + if ((typeInst != NULL) && (resolveParser != NULL)) + { + if (!typeInst->mTypeDef->GetLatest()->HasSource(resolveParser)) + { + continue; + } + } + + workIdx = mMidCompileWorkList.RemoveAt(workIdx); + + BfLogSysM("Handling prior-revision MidCompile on type %s in early-stage UpdateRevisedTypes\n", type); + RebuildDependentTypes(type->ToDependedType()); + //RebuildDependentTypes_MidCompile(type->ToDependedType(), reason); + } + for (auto typeInst : defEmitParentCheckQueue) { if (typeInst->IsDeleting()) @@ -2675,6 +2727,8 @@ void BfContext::UpdateRevisedTypes() RebuildType(type); } } + + BfLogSysM("BfContext::UpdateRevisedTypes done.\n"); } void BfContext::VerifyTypeLookups(BfTypeInstance* typeInst) @@ -3459,6 +3513,7 @@ void BfContext::Cleanup() } } mTypeGraveyard.Clear(); + mGhostDependencies.Clear(); if (!mDeletingModules.IsEmpty()) { diff --git a/IDEHelper/Compiler/BfContext.h b/IDEHelper/Compiler/BfContext.h index 44d883ee..911387d6 100644 --- a/IDEHelper/Compiler/BfContext.h +++ b/IDEHelper/Compiler/BfContext.h @@ -382,6 +382,7 @@ public: BfModule* mScratchModule; BfModule* mUnreifiedModule; HashSet mUsedModuleNames; + HashSet mGhostDependencies; // We couldn't properly rebuild our dependencies Dictionary mProjectModule; Array mModules; Array mDeletingModules; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ca906ca3..7e47a8ca 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5206,7 +5206,12 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe } else if (fieldDef->mIsStatic) { - mModule->CheckStaticAccess(typeInstance); + if ((mModule->mAttributeState == NULL) || (mModule->mAttributeState->mCustomAttributes == NULL) || + (!mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoStaticCtorAttributeTypeDef))) + { + mModule->CheckStaticAccess(typeInstance); + } + auto retVal = mModule->ReferenceStaticField(fieldInstance); bool isStaticCtor = (mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mMethodDef->IsCtorOrInit()) && @@ -6684,7 +6689,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* #endif int vExtOfs = typeInst->GetOrigImplBaseVTableSize(); - vDataIdx = mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int32, 1 + mModule->mCompiler->GetDynCastVDataCount() + mModule->mCompiler->mMaxInterfaceSlots); + + vDataIdx = mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int32, mModule->mCompiler->GetVDataPrefixDataCount() + mModule->mCompiler->GetDynCastVDataCount() + mModule->mCompiler->mMaxInterfaceSlots); vDataIdx = mModule->mBfIRBuilder->CreateAdd(vDataIdx, mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int32, vExtOfs)); BfIRValue extendPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(vDataPtr, vDataIdx); vDataPtr = mModule->mBfIRBuilder->CreateLoad(extendPtr); @@ -7601,7 +7607,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu } else { - mModule->CheckStaticAccess(methodInstance->mMethodInstanceGroup->mOwner); + if (prevBindResult.mPrevVal == NULL) + { + if ((mModule->mAttributeState == NULL) || (mModule->mAttributeState->mCustomAttributes == NULL) || + (!mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoStaticCtorAttributeTypeDef))) + { + mModule->CheckStaticAccess(methodInstance->mMethodInstanceGroup->mOwner); + } + } if (target) { @@ -8613,7 +8626,16 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu // the type has been initialized auto targetTypeInst = target.mType->ToTypeInstance(); if (targetTypeInst != NULL) - mModule->CheckStaticAccess(targetTypeInst); + { + if (prevBindResult.mPrevVal == NULL) + { + if ((mModule->mAttributeState == NULL) || (mModule->mAttributeState->mCustomAttributes == NULL) || + (!mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoStaticCtorAttributeTypeDef))) + { + mModule->CheckStaticAccess(targetTypeInst); + } + } + } } if (methodInstance->mReturnType == NULL) @@ -12535,7 +12557,7 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr) void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) { auto targetValue = mModule->CreateValueFromExpression(dynCastExpr->mTarget); - auto targetType = mModule->ResolveTypeRefAllowUnboundGenerics(dynCastExpr->mTypeRef, BfPopulateType_Data, false); + auto targetType = mModule->ResolveTypeRefAllowUnboundGenerics(dynCastExpr->mTypeRef, BfPopulateType_Data, BfResolveTypeRefFlag_None, false); auto autoComplete = GetAutoComplete(); if (autoComplete != NULL) @@ -18843,6 +18865,10 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m checkedKind = BfCheckedKind_Unchecked; mModule->mAttributeState->mUsed = true; } + if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoStaticCtorAttributeTypeDef)) + { + mModule->mAttributeState->mUsed = true; + } } if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0)) @@ -20967,7 +20993,7 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken } elementValue = mModule->LoadOrAggregateValue(elementValue); - if (!elementValue.mValue.IsConst()) + if (!elemPtrValue.IsConst()) mModule->mBfIRBuilder->CreateAlignedStore(elementValue.mValue, elemPtrValue, checkArrayType->mElementType->mAlign); } } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 9a13232e..72ce6904 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -5391,6 +5391,8 @@ BfIRValue BfModule::CreateClassVDataGlobal(BfTypeInstance* typeInstance, int* ou mClassVDataRefs.TryGetValue(typeInstance, &globalVariablePtr); int numElements = 1; + if (mSystem->mPtrSize == 4) + numElements++; if ((outNumElements != NULL) || (globalVariablePtr == NULL)) { @@ -5432,11 +5434,6 @@ BfIRValue BfModule::CreateClassVDataGlobal(BfTypeInstance* typeInstance, int* ou if (outMangledName != NULL) *outMangledName = classVDataName; - /*if (itr != mClassVDataRefs.end()) - { - globalVariable = itr->second; - }*/ - BfIRValue globalVariable; if (globalVariablePtr != NULL) { @@ -5937,7 +5934,21 @@ BfIRValue BfModule::CreateFieldData(BfFieldInstance* fieldInstance, int customAt return result; } -BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStringIdMap, bool forceReflectFields, bool needsTypeData, bool needsTypeNames, bool needsVData) +void BfModule::CreateSlotOfs(BfTypeInstance* typeInstance) +{ + int virtSlotIdx = -1; + if ((typeInstance != NULL) && (typeInstance->mSlotNum >= 0)) + virtSlotIdx = typeInstance->mSlotNum + mCompiler->GetVDataPrefixDataCount() + mCompiler->GetDynCastVDataCount(); + + // For interfaces we ONLY emit the slot num + StringT<512> slotVarName; + BfMangler::MangleStaticFieldName(slotVarName, mCompiler->GetMangleKind(), typeInstance, "sBfSlotOfs"); + auto intType = GetPrimitiveType(BfTypeCode_Int32); + auto slotNumVar = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapType(intType), true, BfIRLinkageType_External, + GetConstValue32(virtSlotIdx), slotVarName); +} + +BfIRValue BfModule::CreateTypeData(BfType* type, BfCreateTypeDataContext& ctx, bool forceReflectFields, bool needsTypeData, bool needsTypeNames, bool needsVData) { if ((IsHotCompile()) && (!type->mDirty)) return BfIRValue(); @@ -6004,13 +6015,18 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin if ((!mTypeDataRefs.ContainsKey(typeDataSource)) && (typeDataSource != type) && (!mIsComptimeModule)) { - CreateTypeData(typeDataSource, usedStringIdMap, false, true, needsTypeNames, true); + CreateTypeData(typeDataSource, ctx, false, true, needsTypeNames, true); } typeTypeData = CreateClassVDataGlobal(typeDataSource); + + ctx.mReflectTypeSet.Add(typeDataSource); } else - typeTypeData = CreateClassVDataGlobal(typeInstanceType->ToTypeInstance()); + { + //typeTypeData = CreateClassVDataGlobal(typeInstanceType->ToTypeInstance()); + typeTypeData = mBfIRBuilder->CreateConstNull(); + } BfType* longType = GetPrimitiveType(BfTypeCode_Int64); BfType* intType = GetPrimitiveType(BfTypeCode_Int32); @@ -6119,7 +6135,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin int virtSlotIdx = -1; if ((typeInstance != NULL) && (typeInstance->mSlotNum >= 0)) - virtSlotIdx = typeInstance->mSlotNum + 1 + mCompiler->GetDynCastVDataCount(); + virtSlotIdx = typeInstance->mSlotNum + mCompiler->GetVDataPrefixDataCount() + mCompiler->GetDynCastVDataCount(); int memberDataOffset = 0; if (type->IsInterface()) memberDataOffset = virtSlotIdx * mSystem->mPtrSize; @@ -6316,18 +6332,13 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin String classVDataName; if (typeInstance->mSlotNum >= 0) { - // For interfaces we ONLY emit the slot num - StringT<512> slotVarName; - BfMangler::MangleStaticFieldName(slotVarName, mCompiler->GetMangleKind(), typeInstance, "sBfSlotOfs"); - auto intType = GetPrimitiveType(BfTypeCode_Int32); - auto slotNumVar = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapType(intType), true, BfIRLinkageType_External, - GetConstValue32(virtSlotIdx), slotVarName); + CreateSlotOfs(typeInstance); } else if ((typeInstance->IsObject()) && (!typeInstance->IsUnspecializedType()) && (needsVData)) { int dynCastDataElems = 0; int numElements = 1; - int vDataOfs = 1; // The number of intptrs before the iface slot map + int vDataOfs = mCompiler->GetVDataPrefixDataCount(); // The number of intptrs before the iface slot map numElements += mCompiler->mMaxInterfaceSlots; if (!typeInstance->IsInterface()) { @@ -6342,7 +6353,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin classVDataVar = CreateClassVDataGlobal(typeInstance, &expectNumElements, &classVDataName); } - vData.push_back(BfIRValue()); // Type* + for (int i = 0; i < mCompiler->GetVDataPrefixDataCount(); i++) + vData.push_back(BfIRValue()); // Type SizedArray extVTableData; @@ -6752,6 +6764,9 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin // Force override of GetHashCode so we use the pointer address as the hash code for (auto& checkIFace : checkTypeInst->mInterfaces) { + if (checkIFace.mStartVirtualIdx < 0) + continue; + for (int methodIdx = 0; methodIdx < (int)checkIFace.mInterfaceType->mMethodInstanceGroups.size(); methodIdx++) { BfIRValue pushValue; @@ -6976,7 +6991,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin for (auto arg : attr->mCtorArgs) { auto argType = ctorMethodInstance->GetParamType(argIdx); - EncodeAttributeData(typeInstance, argType, arg, data, usedStringIdMap); + EncodeAttributeData(typeInstance, argType, arg, data, ctx.mUsedStringIdMap); argIdx++; } @@ -7494,7 +7509,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin } else { - vDataIdx = 1 + mCompiler->GetDynCastVDataCount() + mCompiler->mMaxInterfaceSlots; + vDataIdx = mCompiler->GetVDataPrefixDataCount() + mCompiler->GetDynCastVDataCount() + mCompiler->mMaxInterfaceSlots; if ((mCompiler->mOptions.mHasVDataExtender) && (mCompiler->IsHotCompile())) { auto typeInst = defaultMethod->mMethodInstanceGroup->mOwner; @@ -7560,7 +7575,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin BfIRType interfaceDataPtrType = mBfIRBuilder->GetPointerTo(mBfIRBuilder->MapType(reflectInterfaceDataType)); Array wantsIfaceMethod; bool wantsIfaceMethods = false; - if (typeInstance->mInterfaces.IsEmpty()) + if ((typeInstance->mInterfaces.IsEmpty()) || (!needsTypeData)) interfaceDataPtr = mBfIRBuilder->CreateConstNull(interfaceDataPtrType); else { @@ -7802,7 +7817,22 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin { BF_ASSERT(!classVDataName.IsEmpty()); - vData[0] = mBfIRBuilder->CreateBitCast(typeDataVar, voidPtrIRType); + //vData[0] = mBfIRBuilder->CreateBitCast(typeDataVar, voidPtrIRType); + + int unboxedTypeId = type->mTypeId; + if (type->IsBoxed()) + unboxedTypeId = type->GetUnderlyingType()->mTypeId; + + if (mSystem->mPtrSize == 4) + { + vData[0] = mBfIRBuilder->CreateIntToPtr(GetConstValue(type->mTypeId, intPtrType), voidPtrIRType); + vData[1] = mBfIRBuilder->CreateIntToPtr(GetConstValue(unboxedTypeId, intPtrType), voidPtrIRType); + } + else + { + vData[0] = mBfIRBuilder->CreateIntToPtr(GetConstValue(((int64)unboxedTypeId << 32) | type->mTypeId, intPtrType), voidPtrIRType); + } + auto classVDataConstDataType = mBfIRBuilder->GetSizedArrayType(voidPtrIRType, (int)vData.size()); auto classVDataConstData = mBfIRBuilder->CreateConstAgg_Value(classVDataConstDataType, vData); @@ -10459,18 +10489,24 @@ void BfModule::EmitObjectAccessCheck(BfTypedValue typedVal) mBfIRBuilder->CreateObjectAccessCheck(typedVal.mValue, !IsOptimized()); } -void BfModule::EmitEnsureInstructionAt() +bool BfModule::WantsDebugHelpers() { if (mBfIRBuilder->mIgnoreWrites) - return; + return false; if (mIsComptimeModule) { // Always add } else if ((mProject == NULL) || (!mHasFullDebugInfo) || (IsOptimized()) || (mCompiler->mOptions.mOmitDebugHelpers)) - return; + return false; + return true; +} +void BfModule::EmitEnsureInstructionAt() +{ + if (!WantsDebugHelpers()) + return; mBfIRBuilder->CreateEnsureInstructionAt(); } @@ -10549,7 +10585,7 @@ void BfModule::EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* tar targetType = GetWrappedStructType(targetType); AddDependency(targetType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); - int inheritanceIdOfs = mSystem->mPtrSize; + int inheritanceIdOfs = mSystem->mPtrSize * mCompiler->GetVDataPrefixDataCount(); vDataPtr = irb->CreateAdd(vDataPtr, irb->CreateConst(BfTypeCode_IntPtr, inheritanceIdOfs)); vDataPtr = irb->CreateIntToPtr(vDataPtr, irb->MapType(int32PtrType)); BfIRValue objInheritanceId = irb->CreateLoad(vDataPtr); @@ -11107,6 +11143,9 @@ BfModuleMethodInstance BfModule::GetMethodInstanceAtIdx(BfTypeInstance* typeInst PopulateType(typeInstance, BfPopulateType_DataAndMethods); + if (methodIdx >= typeInstance->mMethodInstanceGroups.mSize) + return BfModuleMethodInstance(); + auto methodInstance = typeInstance->mMethodInstanceGroups[methodIdx].mDefault; BfMethodDef* methodDef = NULL; @@ -14003,7 +14042,7 @@ BfModule* BfModule::GetOrCreateMethodModule(BfMethodInstance* methodInstance) return declareModule; } -BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags, BfTypeInstance* foreignType) +BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags, BfTypeInstance* foreignType, BfModule* referencingModule) { if (methodDef->mMethodType == BfMethodType_Init) return BfModuleMethodInstance(); @@ -14129,6 +14168,8 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM instModule->mReifyQueued = true; } + BfLogSysM("REIFIED(GetMethodInstance QueueSpecializationRequest): %s %s MethodDef:%p RefModule:%s RefMethod:%p\n", TypeToString(typeInst).c_str(), methodDef->mName.c_str(), methodDef, mModuleName.c_str(), mCurMethodInstance); + // This ensures that the method will actually be created when it gets reified BfMethodSpecializationRequest* specializationRequest = mContext->mMethodSpecializationWorkList.Alloc(); specializationRequest->mFromModule = typeInst->mModule; @@ -14154,7 +14195,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM // Not extern // Create the instance in the proper module and then create a reference in this one - moduleMethodInst = instModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, defFlags, foreignType); + moduleMethodInst = instModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, defFlags, foreignType, this); if (!moduleMethodInst) return moduleMethodInst; tryModuleMethodLookup = true; @@ -14549,8 +14590,18 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM /*if ((!mCompiler->mIsResolveOnly) && (!isReified)) BF_ASSERT(!methodInstance->mIsReified);*/ + if ((!mCompiler->mIsResolveOnly) && (isReified)) + { + auto refModule = referencingModule; + if (refModule == NULL) + refModule = this; + BfLogSysM("REIFIED(GetMethodInstance Reference): %s MethodDef:%p MethodInst:%p RefModule:%s RefMethod:%p\n", methodInstance->mMethodDef->mName.c_str(), methodDef, methodInstance, refModule->mModuleName.c_str(), refModule->mCurMethodInstance); + } + if (methodInstance->mIsReified != isReified) + { BfLogSysM("GetMethodInstance %p Decl_AwaitingReference setting reified to %d\n", methodInstance, isReified); + } if ((!isReified) && ((methodInstance->mDeclModule == NULL) || (!methodInstance->mDeclModule->mIsModuleMutable))) @@ -14975,6 +15026,9 @@ BfIRValue BfModule::GetInterfaceSlotNum(BfTypeInstance* ifaceType) globalValue = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapType(intType), true, BfIRLinkageType_External, value, slotVarName); mInterfaceSlotRefs[ifaceType] = globalValue; + // Make sure we reify + PopulateType(ifaceType, BfPopulateType_Declaration); + AddDependency(ifaceType, mCurTypeInstance, BfDependencyMap::DependencyFlag_StaticValue); } return mBfIRBuilder->CreateAlignedLoad(globalValue/*, "slotOfs"*/, 4); @@ -20087,6 +20141,26 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, if (mAwaitingInitFinish) FinishInit(); + if ((methodInstance->mIsReified) && (!mCompiler->mIsResolveOnly)) + { + BfLogSysM("REIFIED(ProcessMethod): %s %p Module: %s\n", methodInstance->mMethodDef->mName.c_str(), methodInstance, mModuleName.c_str()); + } + + // Reify types that are actually used - they don't get reified during method declaration + if ((!mCompiler->mIsResolveOnly) && (mIsReified)) + { + auto _CheckType = [&](BfType* type) + { + if (!type->IsReified()) + PopulateType(type, BfPopulateType_Declaration); + }; + _CheckType(methodInstance->mReturnType); + for (auto& param : methodInstance->mParams) + { + _CheckType(param.mResolvedType); + } + } + if (!methodInstance->mIsReified) BF_ASSERT(!mIsReified); @@ -22047,8 +22121,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, if ((retVal) && (!retVal.mType->IsVar()) && (expectingType != NULL)) { mCurMethodState->mHadReturn = true; - retVal = LoadOrAggregateValue(retVal); - EmitReturn(retVal); + if (!mCurMethodState->mLeftBlockUncond) + { + retVal = LoadOrAggregateValue(retVal); + EmitReturn(retVal); + } } } } @@ -23719,6 +23796,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool BfTypeState typeState(mCurTypeInstance); SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); + BfModule* resolveModule = mContext->mUnreifiedModule; + if (mCompiler->IsAutocomplete()) prevIsCapturingMethodMatchInfo.Init(mCompiler->mResolvePassData->mAutoComplete->mIsCapturingMethodMatchInfo, false); @@ -23963,7 +24042,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool mIgnoreErrors = false; } - BfResolveTypeRefFlags flags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric); + BfResolveTypeRefFlags flags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_NoReify); if ((((methodInstance->mComptimeFlags & BfComptimeFlag_ConstEval) != 0) || (methodInstance->mIsAutocompleteMethod)) && (methodDef->mReturnTypeRef->IsA())) @@ -24055,14 +24134,14 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { BfTypeUtils::SplatIterate([&](BfType* checkType) { - PopulateType(checkType, BfPopulateType_Data); + resolveModule->PopulateType(checkType, BfPopulateType_Data); }, thisType); } } else { thisType = mCurTypeInstance; - PopulateType(thisType, BfPopulateType_Declaration); + resolveModule->PopulateType(thisType, BfPopulateType_Declaration); } } @@ -24137,7 +24216,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool bool wasGenericParam = false; if (resolvedParamType == NULL) { - BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue); + BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue | BfResolveTypeRefFlag_NoReify); if (paramDef->mParamKind == BfParamKind_ExplicitThis) resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_NoWarnOnMut); resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, resolveFlags); @@ -24388,7 +24467,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool } int argIdx = 0; - PopulateType(methodInstance->mReturnType, BfPopulateType_Data); + resolveModule->PopulateType(methodInstance->mReturnType, BfPopulateType_Data); if ((!methodDef->mIsStatic) && (!methodDef->mHasExplicitThis)) { int thisIdx = methodDef->mHasExplicitThis ? 0 : -1; @@ -24428,7 +24507,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool } else if ((checkType->IsComposite()) && (methodInstance->AllowsSplatting(paramIdx))) { - PopulateType(checkType, BfPopulateType_Data); + resolveModule->PopulateType(checkType, BfPopulateType_Data); if (checkType->IsSplattable()) { bool isSplat = false; @@ -24569,7 +24648,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { auto paramType = methodInstance->GetParamType(paramIdx); if (paramType->IsComposite()) - PopulateType(paramType, BfPopulateType_Data); + resolveModule->PopulateType(paramType, BfPopulateType_Data); if (!methodInstance->IsParamSkipped(paramIdx)) { @@ -24588,7 +24667,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (methodInstance->mIsUnspecializedVariation) return; - PopulateType(resolvedReturnType, BfPopulateType_Data); + resolveModule->PopulateType(resolvedReturnType, BfPopulateType_Data); auto retLLVMType = mBfIRBuilder->MapType(resolvedReturnType); if (resolvedReturnType->IsValuelessType()) retLLVMType = mBfIRBuilder->GetPrimitiveType(BfTypeCode_None); @@ -26023,21 +26102,24 @@ void BfModule::DbgFinish() if (mBfIRBuilder->DbgHasInfo()) { bool needForceLinking = false; - for (auto& ownedType : mOwnedTypeInstances) + if (WantsDebugHelpers()) { - bool hasConfirmedReference = false; - for (auto& methodInstGroup : ownedType->mMethodInstanceGroups) + for (auto& ownedType : mOwnedTypeInstances) { - if ((methodInstGroup.IsImplemented()) && (methodInstGroup.mDefault != NULL) && - (!methodInstGroup.mDefault->mMethodDef->mIsStatic) && (methodInstGroup.mDefault->mIsReified) && (!methodInstGroup.mDefault->mAlwaysInline) && - ((methodInstGroup.mOnDemandKind == BfMethodOnDemandKind_AlwaysInclude) || (methodInstGroup.mOnDemandKind == BfMethodOnDemandKind_Referenced)) && - (methodInstGroup.mHasEmittedReference)) + bool hasConfirmedReference = false; + for (auto& methodInstGroup : ownedType->mMethodInstanceGroups) { - hasConfirmedReference = true; + if ((methodInstGroup.IsImplemented()) && (methodInstGroup.mDefault != NULL) && + (!methodInstGroup.mDefault->mMethodDef->mIsStatic) && (methodInstGroup.mDefault->mIsReified) && (!methodInstGroup.mDefault->mAlwaysInline) && + ((methodInstGroup.mOnDemandKind == BfMethodOnDemandKind_AlwaysInclude) || (methodInstGroup.mOnDemandKind == BfMethodOnDemandKind_Referenced)) && + (methodInstGroup.mHasEmittedReference)) + { + hasConfirmedReference = true; + } } + if ((!hasConfirmedReference) || (ownedType->IsBoxed())) + needForceLinking = true; } - if ((!hasConfirmedReference) || (ownedType->IsBoxed())) - needForceLinking = true; } if ((needForceLinking) && (mProject->mCodeGenOptions.mAsmKind == BfAsmKind_None)) @@ -26153,7 +26235,7 @@ bool BfModule::Finish() codeGenOptions.mWriteLLVMIR = mCompiler->mOptions.mWriteIR; codeGenOptions.mWriteObj = mCompiler->mOptions.mGenerateObj; codeGenOptions.mWriteBitcode = mCompiler->mOptions.mGenerateBitcode; - codeGenOptions.mVirtualMethodOfs = 1 + mCompiler->GetDynCastVDataCount() + mCompiler->mMaxInterfaceSlots; + codeGenOptions.mVirtualMethodOfs = mCompiler->GetVDataPrefixDataCount() + mCompiler->GetDynCastVDataCount() + mCompiler->mMaxInterfaceSlots; codeGenOptions.mDynSlotOfs = mSystem->mPtrSize - mCompiler->GetDynCastVDataCount() * 4; mCompiler->mStats.mIRBytes += mBfIRBuilder->mStream.GetSize(); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index cb7ad5c8..2250300e 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -158,6 +158,12 @@ enum BfLocalVarAssignKind : int8 BfLocalVarAssignKind_Unconditional = 2 }; +struct BfCreateTypeDataContext +{ + Dictionary mUsedStringIdMap; + HashSet mReflectTypeSet; +}; + class BfLocalVariable { public: @@ -1740,6 +1746,7 @@ public: bool HasExecutedOutput(); void SkipObjectAccessCheck(BfTypedValue typedVal); void EmitObjectAccessCheck(BfTypedValue typedVal); + bool WantsDebugHelpers(); void EmitEnsureInstructionAt(); void EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* targetType, BfIRBlock trueBlock, BfIRBlock falseBlock, bool nullSucceeds = false); void EmitDynamicCastCheck(BfTypedValue typedVal, BfType* type, bool allowNull); @@ -1966,7 +1973,7 @@ public: bool ValidateTypeWildcard(BfAstNode* typeRef, bool isAttributeRef); void GetDelegateTypeRefAttributes(BfDelegateTypeRef* delegateTypeRef, BfCallingConvention& callingConvention); BfType* ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, int numGenericArgs = 0); - BfType* ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool resolveGenericParam = true); + BfType* ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, bool resolveGenericParam = true); BfType* ResolveTypeRef_Type(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); BfType* ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); @@ -2062,7 +2069,7 @@ public: void SetMethodDependency(BfMethodInstance* methodInstance); BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); BfModule* GetOrCreateMethodModule(BfMethodInstance* methodInstance); - BfModuleMethodInstance GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None, BfTypeInstance* foreignType = NULL); + BfModuleMethodInstance GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None, BfTypeInstance* foreignType = NULL, BfModule* referencingModule = NULL); BfModuleMethodInstance GetMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); BfMethodInstance* GetOuterMethodInstance(BfMethodInstance* methodInstance); // Only useful for local methods void SetupMethodIdHash(BfMethodInstance* methodInstance); @@ -2075,7 +2082,8 @@ public: BfIRValue CreateTypeDataRef(BfType* type); void EncodeAttributeData(BfTypeInstance* typeInstance, BfType* argType, BfIRValue arg, SizedArrayImpl& data, Dictionary& usedStringIdMap); BfIRValue CreateFieldData(BfFieldInstance* fieldInstance, int customAttrIdx); - BfIRValue CreateTypeData(BfType* type, Dictionary& usedStringIdMap, bool forceReflectFields, bool needsTypeData, bool needsTypeNames, bool needsVData); + void CreateSlotOfs(BfTypeInstance* typeInstance); + BfIRValue CreateTypeData(BfType* type, BfCreateTypeDataContext& ctx, bool forceReflectFields, bool needsTypeData, bool needsTypeNames, bool needsVData); BfIRValue FixClassVData(BfIRValue value); public: diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 0b067e4d..fcacdd08 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -410,7 +410,7 @@ bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* ge SetAndRestoreValue prevIgnoreErrors(mIgnoreErrors, mIgnoreErrors || ignoreErrors); genericTypeInst->mGenericTypeInfo->mValidatedGenericConstraints = true; if (!genericTypeInst->mGenericTypeInfo->mFinishedGenericParams) - PopulateType(genericTypeInst, BfPopulateType_Interfaces_All); + mContext->mUnreifiedModule->PopulateType(genericTypeInst, BfPopulateType_Interfaces_All); if (genericTypeInst->IsTypeAlias()) { @@ -418,7 +418,7 @@ bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* ge if ((underlyingType != NULL) && (underlyingType->IsGenericTypeInstance())) { auto underlyingGenericType = underlyingType->ToGenericTypeInstance(); - PopulateType(underlyingType, BfPopulateType_Declaration); + mContext->mUnreifiedModule->PopulateType(underlyingType, BfPopulateType_Declaration); bool result = ValidateGenericConstraints(typeRef, underlyingGenericType, ignoreErrors); if (underlyingGenericType->mGenericTypeInfo->mHadValidateErrors) genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true; @@ -441,7 +441,7 @@ bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* ge { startGenericParamIdx = typeDef->mOuterType->mGenericParamDefs.mSize + typeDef->mOuterType->mExternalConstraints.mSize; auto outerType = GetOuterType(genericTypeInst); - PopulateType(outerType, BfPopulateType_Declaration); + mContext->mUnreifiedModule->PopulateType(outerType, BfPopulateType_Declaration); if ((outerType->mGenericTypeInfo != NULL) && (outerType->mGenericTypeInfo->mHadValidateErrors)) genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true; } @@ -802,6 +802,11 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) return; } + if ((typeInst != NULL) && (typeInst->mIsReified) && (!mCompiler->mIsResolveOnly)) + { + BfLogSysM("REIFIED(InitType): %s Type:%p FromModule:%s FromMethod:%p\n", TypeToString(resolvedTypeRef).c_str(), resolvedTypeRef, mModuleName.c_str(), prevMethodInstance.mPrevVal); + } + BfLogSysM("%p InitType: %s Type: %p TypeDef: %p Revision:%d\n", mContext, TypeToString(resolvedTypeRef).c_str(), resolvedTypeRef, (typeInst != NULL) ? typeInst->mTypeDef : NULL, mCompiler->mRevision); // When we're autocomplete, we can't do the method processing so we have to add this type to the type work list @@ -1212,6 +1217,14 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType canFastReify = false; } + if (!mCompiler->mIsResolveOnly) + { + for (auto ownedTypes : typeModule->mOwnedTypeInstances) + { + BfLogSysM("REIFIED(PopulateType-Reference): %s %p FromModule:%s FromMethod: %p\n", TypeToString(ownedTypes).c_str(), ownedTypes, mModuleName.c_str(), mCurMethodInstance); + } + } + if (canFastReify) { BfLogSysM("Setting reified type %p in module %p in PopulateType on module awaiting finish\n", resolvedTypeRef, typeModule); @@ -1292,7 +1305,17 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL); SetAndRestoreValue prevMethodState(mCurMethodState, NULL); - BF_ASSERT((resolvedTypeRef->mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) == 0); + if ((resolvedTypeRef->mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) != 0) + { + if (mContext->mGhostDependencies.Contains(resolvedTypeRef)) + { + // Not a nice state, but we should be able to recover + return; + } + + InternalError("Attempting PopulateType on deleted type"); + return; + } bool isNew = resolvedTypeRef->mDefineState == BfTypeDefineState_Undefined; if (isNew) @@ -8268,7 +8291,7 @@ BfType* BfModule::ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType auto typeDefTypeRef = mContext->mTypeDefTypeRefPool.Get(); typeDefTypeRef->mTypeDef = typeDef; - auto resolvedtypeDefType = ResolveTypeRef(typeDefTypeRef, populateType); + auto resolvedtypeDefType = ResolveTypeRef(typeDefTypeRef, populateType, resolveFlags); if (resolvedtypeDefType == NULL) { mContext->mTypeDefTypeRefPool.GiveBack(typeDefTypeRef); @@ -11347,7 +11370,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } } - return ResolveTypeResult(typeRef, ResolveTypeDef(typeDef, genericArgs, populateType), populateType, resolveFlags); + return ResolveTypeResult(typeRef, ResolveTypeDef(typeDef, genericArgs, populateType, resolveFlags), populateType, resolveFlags); } } } @@ -12635,7 +12658,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); } -BfType* BfModule::ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType, bool resolveGenericParam) +BfType* BfModule::ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags, bool resolveGenericParam) { if (auto genericTypeRef = BfNodeDynCast(typeRef)) { @@ -12648,7 +12671,7 @@ BfType* BfModule::ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, B BfTypeVector typeVector; for (int i = 0; i < (int)genericTypeDef->mGenericParamDefs.size(); i++) typeVector.push_back(GetGenericParamType(BfGenericParamKind_Type, i)); - auto result = ResolveTypeDef(genericTypeDef, typeVector, populateType); + auto result = ResolveTypeDef(genericTypeDef, typeVector, populateType, resolveFlags); if ((result != NULL) && (genericTypeRef->mCommas.size() + 1 != genericTypeDef->mGenericParamDefs.size())) { SetAndRestoreValue prevTypeInstance(mCurTypeInstance, result->ToTypeInstance()); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index c4d67043..18b39392 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1270,11 +1270,12 @@ bool BfMethodInstance::WasGenericParam(int paramIdx) bool BfMethodInstance::IsParamSkipped(int paramIdx) { + auto resolveModule = GetModule()->mContext->mUnreifiedModule; if (paramIdx == -1) return false; BfType* paramType = GetParamType(paramIdx); if ((paramType->CanBeValuelessType()) && (paramType->IsDataIncomplete())) - GetModule()->PopulateType(paramType, BfPopulateType_Data); + resolveModule->PopulateType(paramType, BfPopulateType_Data); if ((paramType->IsValuelessType()) && (!paramType->IsMethodRef())) return true; return false; @@ -1344,7 +1345,7 @@ int BfMethodInstance::DbgGetVirtualMethodNum() module->HadSlotCountDependency(); int vDataIdx = -1; - vDataIdx = 1 + module->mCompiler->mMaxInterfaceSlots; + vDataIdx = module->mCompiler->GetVDataPrefixDataCount() + module->mCompiler->mMaxInterfaceSlots; vDataIdx += module->mCompiler->GetDynCastVDataCount(); if ((module->mCompiler->mOptions.mHasVDataExtender) && (module->mCompiler->IsHotCompile())) { @@ -1375,7 +1376,9 @@ int BfMethodInstance::DbgGetVirtualMethodNum() void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, SizedArrayImpl& paramTypes, bool forceStatic) { - module->PopulateType(mReturnType); + BfModule* resolveModule = module->mContext->mUnreifiedModule; + + resolveModule->PopulateType(mReturnType); BfTypeCode loweredReturnTypeCode = BfTypeCode_None; BfTypeCode loweredReturnTypeCode2 = BfTypeCode_None; @@ -1459,7 +1462,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, else { if ((checkType->IsComposite()) && (checkType->IsIncomplete())) - module->PopulateType(checkType, BfPopulateType_Data); + resolveModule->PopulateType(checkType, BfPopulateType_Data); if (checkType->IsMethodRef()) { @@ -1492,7 +1495,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, } if (checkType->CanBeValuelessType()) - module->PopulateType(checkType, BfPopulateType_Data); + resolveModule->PopulateType(checkType, BfPopulateType_Data); if ((checkType->IsValuelessType()) && (!checkType->IsMethodRef())) continue; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 8ff31bc9..6bed7ee3 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -6714,12 +6714,18 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) PopulateType(itrInterface, BfPopulateType_Full_Force); getNextMethodInst = GetMethodByName(itrInterface, "GetNext"); } - BF_ASSERT(getNextMethodInst); - nextResult = BfTypedValue(CreateAlloca(getNextMethodInst.mMethodInstance->mReturnType), getNextMethodInst.mMethodInstance->mReturnType, true); - - if (nextResult.mType->IsGenericTypeInstance()) + if (getNextMethodInst) { - nextEmbeddedType = ((BfTypeInstance*)nextResult.mType)->mGenericTypeInfo->mTypeGenericArguments[0]; + nextResult = BfTypedValue(CreateAlloca(getNextMethodInst.mMethodInstance->mReturnType), getNextMethodInst.mMethodInstance->mReturnType, true); + + if (nextResult.mType->IsGenericTypeInstance()) + { + nextEmbeddedType = ((BfTypeInstance*)nextResult.mType)->mGenericTypeInfo->mTypeGenericArguments[0]; + } + } + else + { + InternalError("Failed to find GetNext"); } } if (nextEmbeddedType == NULL) diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 96b90544..e4ec9928 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -3865,8 +3865,8 @@ addr_ce CeContext::GetReflectType(int typeId) if (bfType->mDefineState != BfTypeDefineState_CETypeInit) ceModule->PopulateType(bfType, BfPopulateType_DataAndMethods); - Dictionary usedStringMap; - auto irData = ceModule->CreateTypeData(bfType, usedStringMap, true, true, true, false); + BfCreateTypeDataContext createTypeDataCtx; + auto irData = ceModule->CreateTypeData(bfType, createTypeDataCtx, true, true, true, false); BeValue* beValue = NULL; if (auto constant = mCeMachine->mCeModule->mBfIRBuilder->GetConstant(irData)) diff --git a/IDEHelper/DbgModule.cpp b/IDEHelper/DbgModule.cpp index d98b318b..90334231 100644 --- a/IDEHelper/DbgModule.cpp +++ b/IDEHelper/DbgModule.cpp @@ -833,6 +833,11 @@ bool DbgSubprogram::IsLambda() return StringView(mName).Contains('$'); } +int DbgSubprogram::GetByteCount() +{ + return (int)(mBlock.mHighPC - mBlock.mLowPC); +} + ////////////////////////////////////////////////////////////////////////// DbgSubprogram::~DbgSubprogram() @@ -5783,7 +5788,7 @@ bool DbgModule::ReadCOFF(DataStream* stream, DbgModuleKind moduleKind) Array sectionHeaders; sectionHeaders.Resize(ntHdr.mFileHeader.mNumberOfSections); - mSectionRVAs.Resize(sectionHeaders.size() + 1); + mSectionHeaders.Resize(sectionHeaders.size() + 1); Array sectionNames; sectionNames.Resize(ntHdr.mFileHeader.mNumberOfSections); @@ -5792,7 +5797,7 @@ bool DbgModule::ReadCOFF(DataStream* stream, DbgModuleKind moduleKind) for (int sectNum = 0; sectNum < ntHdr.mFileHeader.mNumberOfSections; sectNum++) { - mSectionRVAs[sectNum] = sectionHeaders[sectNum].mVirtualAddress; + mSectionHeaders[sectNum] = sectionHeaders[sectNum]; } int tlsSection = -1; @@ -5827,6 +5832,7 @@ bool DbgModule::ReadCOFF(DataStream* stream, DbgModuleKind moduleKind) } DbgSection dwSection; + dwSection.mName = name; dwSection.mIsExecutable = (sectHdr.mCharacteristics & IMAGE_SCN_MEM_EXECUTE) != 0; dwSection.mAddrStart = sectHdr.mVirtualAddress; dwSection.mAddrLength = BF_MAX(sectHdr.mSizeOfRawData, sectHdr.mVirtualSize); @@ -6290,7 +6296,7 @@ bool DbgModule::ReadCOFF(DataStream* stream, DbgModuleKind moduleKind) } } else - targetAddr = mSectionRVAs[symInfo->mSectionNum - 1] + symInfo->mValue; + targetAddr = mSectionHeaders[symInfo->mSectionNum - 1].mVirtualAddress + symInfo->mValue; if (((targetAddr != 0) || (isTLS)) && (name[0] != '.')) diff --git a/IDEHelper/DbgModule.h b/IDEHelper/DbgModule.h index c2dd9eda..813401d8 100644 --- a/IDEHelper/DbgModule.h +++ b/IDEHelper/DbgModule.h @@ -442,6 +442,7 @@ public: bool IsGenericMethod(); bool ThisIsSplat(); bool IsLambda(); + int GetByteCount(); DbgSubprogram* GetRootInlineParent() { @@ -823,6 +824,7 @@ public: addr_target mAddress; int mCompileUnitId; int mLength; + int mSection; }; class DbgCompileUnit @@ -874,6 +876,7 @@ public: class DbgSection { public: + String mName; addr_target mAddrStart; addr_target mAddrLength; bool mWritingEnabled; @@ -1183,7 +1186,7 @@ public: bool mIsDwarf64; HashSet mSrcFileDeferredRefs; - Array mSectionRVAs; + Array mSectionHeaders; SLIList mDeferredSymbols; Beefy::OwnedVector mDeferredHotResolveList; Array mHotTargetSections; diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index 9118690f..d15576d5 100644 --- a/IDEHelper/DebugManager.cpp +++ b/IDEHelper/DebugManager.cpp @@ -1548,6 +1548,13 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetModulesInfo() return outString.c_str(); } +BF_EXPORT const char* BF_CALLTYPE Debugger_GetModuleInfo(const char* moduleName) +{ + String& outString = *gTLStrReturn.Get(); + outString = gDebugger->GetModuleInfo(moduleName); + return outString.c_str(); +} + BF_EXPORT void BF_CALLTYPE Debugger_CancelSymSrv() { gDebugger->CancelSymSrv(); diff --git a/IDEHelper/Debugger.h b/IDEHelper/Debugger.h index cdffc565..34a41159 100644 --- a/IDEHelper/Debugger.h +++ b/IDEHelper/Debugger.h @@ -343,6 +343,7 @@ public: virtual String FindLineCallAddresses(intptr address) = 0; virtual String GetCurrentException() = 0; virtual String GetModulesInfo() = 0; + virtual String GetModuleInfo(const StringImpl& moduleName) { return ""; } virtual void SetAliasPath(const StringImpl& origPath, const StringImpl& localPath) = 0; virtual void CancelSymSrv() = 0; virtual bool HasPendingDebugLoads() = 0; diff --git a/IDEHelper/HotScanner.cpp b/IDEHelper/HotScanner.cpp index e623821e..0a67b0d6 100644 --- a/IDEHelper/HotScanner.cpp +++ b/IDEHelper/HotScanner.cpp @@ -8,6 +8,8 @@ USING_NS_BF_DBG; DbgHotScanner::DbgHotScanner(WinDebugger* debugger) { mDebugger = debugger; + mBfTypesInfoAddr = 0; + mDbgGCData = { 0 }; } NS_BF_DBG_BEGIN @@ -255,20 +257,25 @@ void DbgHotScanner::ScanSpan(TCFake::Span* span, int expectedStartPage, int memK int* typeIdPtr = NULL; if (mFoundClassVDataAddrs.TryAdd(classVDataAddr, NULL, &typeIdPtr)) { - addr_target typeAddr = mDebugger->ReadMemory(classVDataAddr); - Fake_Type_Data typeData; - mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData); - - *typeIdPtr = typeData.mTypeId; - _MarkTypeUsed(typeData.mTypeId, elementSize); - if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0) + if (mBfTypesInfoAddr > 0) { - Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize); - if (mFoundFuncPtrs.Add(dlg->mFuncPtr)) + addr_target typeId = mDebugger->ReadMemory(classVDataAddr); + addr_target arrayAddr = mBfTypesInfoAddr + typeId * sizeof(addr_target); + addr_target typeAddr = mDebugger->ReadMemory(arrayAddr); + Fake_Type_Data typeData; + mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData); + + *typeIdPtr = typeData.mTypeId; + _MarkTypeUsed(typeData.mTypeId, elementSize); + if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0) { - auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None); - if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef)) - AddSubProgram(subProgram, true, "D "); + Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize); + if (mFoundFuncPtrs.Add(dlg->mFuncPtr)) + { + auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None); + if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef)) + AddSubProgram(subProgram, true, "D "); + } } } } @@ -358,6 +365,7 @@ void DbgHotScanner::Scan(DbgHotResolveFlags flags) { if ((module->mFilePath.Contains("Beef")) && (module->mFilePath.Contains("Dbg"))) { + module->ParseTypeData(); module->ParseSymbolData(); auto entry = module->mSymbolNameMap.Find("gGCDbgData"); if ((entry != NULL) && (entry->mValue != NULL)) @@ -365,6 +373,44 @@ void DbgHotScanner::Scan(DbgHotResolveFlags flags) } } + auto module = mDebugger->mDebugTarget->mTargetBinary; + if (module->mBfTypesInfoAddr == 0) + { + module->mBfTypesInfoAddr = -1; + auto typeTypeEntry = module->FindType("System.Type", DbgLanguage_Beef); + if ((typeTypeEntry != NULL) && (typeTypeEntry->mValue != NULL)) + { + auto typeType = typeTypeEntry->mValue; + module->mBfTypeType = typeType; + if (typeType->mNeedsGlobalsPopulated) + typeType->mCompileUnit->mDbgModule->PopulateTypeGlobals(typeType); + + for (auto member : typeType->mMemberList) + { + if ((member->mIsStatic) && (member->mName != NULL) && (strcmp(member->mName, "sTypes") == 0) && (member->mLocationData != NULL)) + { + DbgAddrType addrType; + module->mBfTypesInfoAddr = member->mCompileUnit->mDbgModule->EvaluateLocation(NULL, member->mLocationData, member->mLocationLen, NULL, &addrType); + } + } + + if (module->mBfTypesInfoAddr <= 0) + { + auto entry = module->mSymbolNameMap.Find( +#ifdef BF_DBG_64 + "?sTypes@Type@System@bf@@2PEAPEAV123@A" +#else + "?sTypes@Type@System@bf@@2PAPAV123@A" +#endif + ); + + if (entry) + module->mBfTypesInfoAddr = entry->mValue->mAddress; + } + } + } + mBfTypesInfoAddr = module->mBfTypesInfoAddr; + if (gcDbgDataAddr == 0) return; diff --git a/IDEHelper/HotScanner.h b/IDEHelper/HotScanner.h index b52944b0..36e4e363 100644 --- a/IDEHelper/HotScanner.h +++ b/IDEHelper/HotScanner.h @@ -84,6 +84,7 @@ class DbgHotScanner public: WinDebugger* mDebugger; DbgGCData mDbgGCData; + addr_target mBfTypesInfoAddr; Beefy::Dictionary mFoundClassVDataAddrs; Beefy::Dictionary mFoundRawAllocDataAddrs; Beefy::Dictionary mFoundTypeAddrs; diff --git a/IDEHelper/Tests/BeefSpace.toml b/IDEHelper/Tests/BeefSpace.toml index e1560daa..60735120 100644 --- a/IDEHelper/Tests/BeefSpace.toml +++ b/IDEHelper/Tests/BeefSpace.toml @@ -8,6 +8,9 @@ StartupProject = "Tests" [Configs.Debug.Win64] IntermediateType = "ObjectAndIRCode" +[Configs.Debug.Win32] +IntermediateType = "ObjectAndIRCode" + [Configs.Test.Win64] IntermediateType = "ObjectAndIRCode" COptimizationLevel = "O2" diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 84a91ed6..3081d340 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -12872,6 +12872,210 @@ String WinDebugger::GetModulesInfo() return str; } +String WinDebugger::GetModuleInfo(const StringImpl& modulePath) +{ + AutoCrit autoCrit(mDebugManager->mCritSect); + + String result; + + for (auto dbgModule : mDebugTarget->mDbgModules) + { + if (modulePath.Equals(dbgModule->mFilePath, StringImpl::CompareKind_OrdinalIgnoreCase)) + { + dbgModule->ParseGlobalsData(); + dbgModule->PopulateStaticVariableMap(); + + auto coff = (COFF*)dbgModule; + coff->ParseCompileUnits(); + + int fileSize = 0; + // + { + FileStream fs; + fs.Open(coff->mFilePath, "rb"); + fileSize = fs.GetSize(); + } + + result += StrFormat("Path: %s FileSize:%0.2fk MemoryImage:%0.2fk\n", coff->mFilePath.c_str(), fileSize / 1024.0f, coff->mImageSize / 1024.0f); + + result += "Sections:\n"; + for (auto& section : coff->mSections) + { + result += StrFormat("\t%s\t%0.2fk\n", section.mName.c_str(), (section.mAddrLength) / 1024.0f); + } + result += "\n"; + + result += "Compile Units:\n"; + for (auto compileUnit : dbgModule->mCompileUnits) + { + coff->MapCompileUnitMethods(compileUnit); + result += StrFormat("\t%s PCRange:%0.2fk\n", compileUnit->mName.c_str(), (compileUnit->mHighPC - compileUnit->mLowPC) / 1024.0f); + } + result += "\n"; + + Array moduleInfos; + for (auto moduleInfo : coff->mCvModuleInfo) + { + if (moduleInfo->mSectionContrib.mSize > 0) + moduleInfos.Add(moduleInfo); + } + moduleInfos.Sort([](CvModuleInfo* lhs, CvModuleInfo* rhs) + { + return lhs->mSectionContrib.mSize > rhs->mSectionContrib.mSize; + }); + + int totalContrib = 0; + result += "CV Module Info:\n"; + for (auto moduleInfo : moduleInfos) + { + auto section = coff->mSections[moduleInfo->mSectionContrib.mSection - 1]; + + result += StrFormat("\t%s\t%s\t%0.2fk\t%@-%@\n", moduleInfo->mModuleName, section.mName.c_str(), (moduleInfo->mSectionContrib.mSize) / 1024.0f, + coff->GetSectionAddr(moduleInfo->mSectionContrib.mSection, moduleInfo->mSectionContrib.mOffset), + coff->GetSectionAddr(moduleInfo->mSectionContrib.mSection, moduleInfo->mSectionContrib.mOffset + moduleInfo->mSectionContrib.mSize)); + totalContrib += moduleInfo->mSectionContrib.mSize; + } + result += StrFormat("\tTOTAL: %0.2fk\n", (totalContrib) / 1024.0f); + result += "\n"; + + addr_target minAddr = 0; + Array contribs; + for (auto itr = mDebugTarget->mContribMap.begin(); itr != mDebugTarget->mContribMap.end(); ++itr) + { + auto contrib = *itr; + if (contrib->mDbgModule != coff) + continue; + + if (contrib->mAddress < minAddr) + continue; + + minAddr = contrib->mAddress + contrib->mLength; + + auto section = &coff->mSectionHeaders[contrib->mSection - 1]; + if (section->mSizeOfRawData <= 0) + continue; + + contribs.Add(contrib); + } + contribs.Sort([](DbgCompileUnitContrib* lhs, DbgCompileUnitContrib* rhs) + { + return lhs->mLength > rhs->mLength; + }); + + totalContrib = 0; + result += "Contribs:\n"; + for (auto contrib : contribs) + { + auto cvModule = coff->mCvModuleInfo[contrib->mCompileUnitId]; + auto section = &coff->mSectionHeaders[contrib->mSection - 1]; + result += StrFormat("\t%s\t%s\t%0.2fk\t%@\n", cvModule->mModuleName, section->mName, (contrib->mLength)/1024.0f, contrib->mAddress); + totalContrib += contrib->mLength; + } + result += StrFormat("\tTOTAL: %0.2fk\n", (totalContrib) / 1024.0f); + result += "\n"; + + struct SymbolEntry + { + const char* mName; + addr_target mAddress; + int mSize; + }; + Array symbolEntries; + + for (auto symbol : mDebugTarget->mSymbolMap) + { + if (symbol->mDbgModule != coff) + continue; + + if (!symbolEntries.IsEmpty()) + { + auto lastSymbol = &symbolEntries.back(); + if (lastSymbol->mSize == 0) + lastSymbol->mSize = symbol->mAddress - lastSymbol->mAddress; + } + + SymbolEntry symbolEntry; + symbolEntry.mName = symbol->mName; + symbolEntry.mAddress = symbol->mAddress; + symbolEntry.mSize = 0; + symbolEntries.Add(symbolEntry); + } + if (!symbolEntries.IsEmpty()) + { + auto lastSymbol = &symbolEntries.back(); + for (auto contrib : contribs) + { + if ((lastSymbol->mAddress >= contrib->mAddress) && (lastSymbol->mAddress < contrib->mAddress + contrib->mLength)) + { + lastSymbol->mSize = (contrib->mAddress + contrib->mLength) - lastSymbol->mAddress; + break; + } + } + } + symbolEntries.Sort([](const SymbolEntry& lhs, const SymbolEntry& rhs) + { + return lhs.mSize > rhs.mSize; + }); + + totalContrib = 0; + result += "Symbols:\n"; + for (auto symbolEntry : symbolEntries) + { + result += StrFormat("\t%s\t%0.2fk\t%@\n", symbolEntry.mName, (symbolEntry.mSize) / 1024.0f, symbolEntry.mAddress); + totalContrib += symbolEntry.mSize; + } + result += StrFormat("\tTOTAL: %0.2fk\n", (totalContrib) / 1024.0f); + result += "\n"; + + ////////////////////////////////////////////////////////////////////////// + + totalContrib = 0; + result += "Static Variables:\n"; + for (auto& variable : coff->mStaticVariables) + { + result += StrFormat("\t%s\t%0.2fk\n", variable->mName, (variable->mType->GetByteCount()) / 1024.0f); + totalContrib += variable->mType->GetByteCount(); + } + result += StrFormat("\tTOTAL: %0.2fk\n", (totalContrib) / 1024.0f); + result += "\n"; + + totalContrib = 0; + result += "Methods:\n"; + Array methods; + for (int typeIdx = 0; typeIdx < coff->mTypes.mSize; typeIdx++) + { + auto type = coff->mTypes[typeIdx]; + type->PopulateType(); + for (auto method : type->mMethodList) + methods.Add(method); + } + for (auto compileUnit : dbgModule->mCompileUnits) + { + for (auto method : compileUnit->mOrphanMethods) + methods.Add(method); + } + methods.Sort([](DbgSubprogram* lhs, DbgSubprogram* rhs) + { + return lhs->GetByteCount() > rhs->GetByteCount(); + }); + for (auto method : methods) + { + int methodSize = method->GetByteCount(); + if (methodSize <= 0) + continue; + auto name = method->ToString(); + result += StrFormat("\t%s\t%0.2fk\n", name.c_str(), methodSize / 1024.0f); + totalContrib += methodSize; + } + + result += StrFormat("\tTOTAL: %0.2fk\n", (totalContrib) / 1024.0f); + result += "\n"; + } + } + + return result; +} + void WinDebugger::CancelSymSrv() { AutoCrit autoCrit(mDebugManager->mCritSect); diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index fb699763..3843b698 100644 --- a/IDEHelper/WinDebugger.h +++ b/IDEHelper/WinDebugger.h @@ -656,6 +656,7 @@ public: virtual String GetCurrentException() override; virtual void SetAliasPath(const StringImpl& origPath, const StringImpl& localPath) override; virtual String GetModulesInfo() override; + virtual String GetModuleInfo(const StringImpl& moduleName) override; virtual void CancelSymSrv() override; virtual bool HasPendingDebugLoads() override; virtual int LoadImageForModule(const StringImpl& moduleName, const StringImpl& debugFileName) override; diff --git a/bin/test_build.bat b/bin/test_build.bat index 4e3b35f2..cf228ceb 100644 --- a/bin/test_build.bat +++ b/bin/test_build.bat @@ -1,4 +1,3 @@ - @ECHO --------------------------- Beef Test_Build.Bat Version 1 --------------------------- @SET P4_CHANGELIST=%1 @@ -33,6 +32,20 @@ IDE\Tests\SysMSVCRT\build\Debug_Win64\SysMSVCRT\SysMSVCRT.exe 1000 234 IDE\dist\BeefBuild_d -proddir=BeefLibs\corlib -test @IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +@ECHO Building Tiny +bin\RunWithStats IDE\dist\BeefBuild -proddir=IDE\Tests\Tiny -clean -config=Release +set size=0 +FOR /F "usebackq" %%A IN ('IDE\Tests\Tiny\build\Release_Win64\Tiny\Tiny.exe') DO set size=%%~zA +echo Tiny executable size: %size% (expected 13824, max 16000) +if %size% LSS 10000 ( + echo TINY executable not found? + goto :HADERROR +) +if %size% GTR 16000 ( + echo TINY executable is too large! + goto :HADERROR +) + @ECHO Building BeefIDE_d with BeefBuild_d bin\RunAndWait IDE\dist\BeefPerf.exe -cmd="Nop()" @IF %ERRORLEVEL% NEQ 0 GOTO FAILPERF_START