Bladeren bron

Extensive runtime refactor to reduce generated executable sizes

Brian Fiete 1 jaar geleden
bovenliggende
commit
ddd9b1b218
74 gewijzigde bestanden met toevoegingen van 2507 en 710 verwijderingen
  1. 6 9
      BeefLibs/FMOD/src/FMod.bf
  2. 6 0
      BeefLibs/corlib/src/Attribute.bf
  3. 61 12
      BeefLibs/corlib/src/Console.bf
  4. 8 1
      BeefLibs/corlib/src/Diagnostics/Contracts/Contracts.bf
  5. 12 4
      BeefLibs/corlib/src/Diagnostics/Debug.bf
  6. 4 0
      BeefLibs/corlib/src/Double.bf
  7. 18 1
      BeefLibs/corlib/src/Environment.bf
  8. 4 0
      BeefLibs/corlib/src/Float.bf
  9. 1 1
      BeefLibs/corlib/src/GC.bf
  10. 8 0
      BeefLibs/corlib/src/Int.bf
  11. 0 5
      BeefLibs/corlib/src/Int64.bf
  12. 263 28
      BeefLibs/corlib/src/Internal.bf
  13. 16 1
      BeefLibs/corlib/src/Math.bf
  14. 29 2
      BeefLibs/corlib/src/NumberFormatter.bf
  15. 68 24
      BeefLibs/corlib/src/Object.bf
  16. 3 3
      BeefLibs/corlib/src/OperatingSystem.bf
  17. 273 2
      BeefLibs/corlib/src/Platform.bf
  18. 3 3
      BeefLibs/corlib/src/Pointer.bf
  19. 233 50
      BeefLibs/corlib/src/Runtime.bf
  20. 1 1
      BeefLibs/corlib/src/Span.bf
  21. 19 14
      BeefLibs/corlib/src/String.bf
  22. 1 1
      BeefLibs/corlib/src/Test.bf
  23. 34 5
      BeefLibs/corlib/src/Text/Encoding.bf
  24. 74 41
      BeefLibs/corlib/src/Threading/Thread.bf
  25. 19 10
      BeefLibs/corlib/src/Type.bf
  26. 8 0
      BeefLibs/corlib/src/UInt.bf
  27. 0 2
      BeefLibs/corlib/src/UInt64.bf
  28. 15 13
      BeefRT/rt/BfObjects.h
  29. 101 100
      BeefRT/rt/Internal.cpp
  30. 2 2
      BeefRT/rt/Object.cpp
  31. 42 39
      BeefRT/rt/Thread.cpp
  32. 2 0
      BeefySysLib/platform/PlatformInterface.h
  33. 42 46
      BeefySysLib/platform/win/CrashCatcher.cpp
  34. 60 12
      BeefySysLib/platform/win/Platform.cpp
  35. 75 40
      BeefySysLib/util/String.h
  36. 1 1
      IDE/BeefProj.toml
  37. 8 0
      IDE/Tests/Tiny/BeefProj.toml
  38. 26 0
      IDE/Tests/Tiny/BeefSpace.toml
  39. 13 0
      IDE/Tests/Tiny/src/Program.bf
  40. 14 8
      IDE/mintest/minlib/src/System/Attribute.bf
  41. 8 1
      IDE/mintest/minlib/src/System/Internal.bf
  42. 131 67
      IDE/mintest/minlib/src/System/Object.bf
  43. 5 1
      IDE/mintest/minlib/src/System/Type.bf
  44. 5 3
      IDE/mintest/src/main.bf
  45. 9 3
      IDE/src/BuildContext.bf
  46. 7 0
      IDE/src/BuildOptions.bf
  47. 6 1
      IDE/src/Compiler/BfCompiler.bf
  48. 8 0
      IDE/src/Debugger/DebugManager.bf
  49. 7 0
      IDE/src/IDEApp.bf
  50. 26 1
      IDE/src/Workspace.bf
  51. 14 0
      IDE/src/ui/ModulePanel.bf
  52. 2 0
      IDE/src/ui/WorkspaceProperties.bf
  53. 8 4
      IDEHelper/COFF.cpp
  54. 77 18
      IDEHelper/Compiler/BfCompiler.cpp
  55. 2 0
      IDEHelper/Compiler/BfCompiler.h
  56. 92 37
      IDEHelper/Compiler/BfContext.cpp
  57. 1 0
      IDEHelper/Compiler/BfContext.h
  58. 32 6
      IDEHelper/Compiler/BfExprEvaluator.cpp
  59. 130 48
      IDEHelper/Compiler/BfModule.cpp
  60. 11 3
      IDEHelper/Compiler/BfModule.h
  61. 31 8
      IDEHelper/Compiler/BfModuleTypeUtils.cpp
  62. 8 5
      IDEHelper/Compiler/BfResolvedTypeUtils.cpp
  63. 10 4
      IDEHelper/Compiler/BfStmtEvaluator.cpp
  64. 2 2
      IDEHelper/Compiler/CeMachine.cpp
  65. 9 3
      IDEHelper/DbgModule.cpp
  66. 4 1
      IDEHelper/DbgModule.h
  67. 7 0
      IDEHelper/DebugManager.cpp
  68. 1 0
      IDEHelper/Debugger.h
  69. 58 12
      IDEHelper/HotScanner.cpp
  70. 1 0
      IDEHelper/HotScanner.h
  71. 3 0
      IDEHelper/Tests/BeefSpace.toml
  72. 204 0
      IDEHelper/WinDebugger.cpp
  73. 1 0
      IDEHelper/WinDebugger.h
  74. 14 1
      bin/test_build.bat

+ 6 - 9
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);

+ 6 - 0
BeefLibs/corlib/src/Attribute.bf

@@ -172,6 +172,12 @@ namespace System
 	    
 	}
 
+	[AttributeUsage(.MemberAccess)]
+	public struct NoStaticCtorAttribute : Attribute
+	{
+	    
+	}
+
 	
 	[AttributeUsage(.Block)]
 	public struct ConstSkipAttribute : Attribute

+ 61 - 12
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<delegate void (CancelKind cancelKind, ref bool terminate)> 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<delegate void (CancelKind cancelKind, ref bool terminate)> 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<delegate void (CancelKind cancelKind, ref bool terminate)> 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)

+ 8 - 1
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
 
         /// <summary>
         /// This method is used internally to trigger a failure indicating to the "programmer" that he is using the interface incorrectly.

+ 12 - 4
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

+ 4 - 0
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)
 		{

+ 18 - 1
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;
 

+ 4 - 0
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)
 		{

+ 1 - 1
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)]

+ 8 - 0
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;
 

+ 0 - 5
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)

+ 263 - 28
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();
+
+		[CallingConvention(.Cdecl), AlwaysInclude]
+		static void Shutdown()
+		{
+			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();
+		}
 
-		static void* sModuleHandle;
 		[AlwaysInclude]
-		static void SetModuleHandle(void* handle)
+		public static void* VirtualAlloc(int size, bool canExecute, bool canWrite)
 		{
-			sModuleHandle = handle;
+			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

+ 16 - 1
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)
 		{

+ 29 - 2
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);

+ 68 - 24
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
+			classVData = mClassVData;
+#endif
+
+#if BF_32_BIT
+			Type type = Type.[Friend]GetType_(classVData.mType2);
 #else
-            type = mClassVData.mType;
+			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()
         {

+ 3 - 3
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

+ 273 - 2
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
 		{

+ 3 - 3
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);
 		}
 	}
 }

+ 233 - 50
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<Monitor> sMonitor ~ _.Dispose();
+			public static List<ErrorHandler> sErrorHandlers ~ DeleteContainerAndItems!(_);
+			public static bool sInsideErrorHandler;
+		}
 
 		static RtFlags sExtraFlags;
-		static AllocWrapper<Monitor> sMonitor ~ _.Dispose();
-		static List<ErrorHandler> 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<void> RemoveErrorHandler(ErrorHandler handler)
+		public static Result<void> 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

+ 1 - 1
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);
 		}
 

+ 19 - 14
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<String> sInterns = new .() ~ delete _;
+			public static List<String> 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<String> sInterns = new .() ~ delete _;
-		static List<String> 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()

+ 1 - 1
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);

+ 34 - 5
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<T>(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<ASCIIEncoding>(ref sASCII);
+		public static UTF8Encoding UTF8 => GetEncoding<UTF8Encoding>(ref sUTF8);
+		public static UTF8EncodingWithBOM UTF8WithBOM => GetEncoding<UTF8EncodingWithBOM>(ref sUTF8WithBOM);
+		public static UTF16Encoding UTF16 => GetEncoding<UTF16Encoding>(ref sUTF16);
+		public static UTF16EncodingWithBOM UTF16WithBOM => GetEncoding<UTF16EncodingWithBOM>(ref sUTF16WithBOM);
 
 		public abstract int GetCharUnitSize();
 		public abstract int GetEncodedLength(char32 c);

+ 74 - 41
BeefLibs/corlib/src/Threading/Thread.bf

@@ -26,7 +26,7 @@ namespace System.Threading
 		static Event<delegate void()> sOnExit ~ _.Dispose();
 		Event<delegate void()> 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
     }
 }

+ 19 - 10
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<Type>
@@ -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.

+ 8 - 0
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;
 

+ 0 - 2
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)

+ 15 - 13
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);
 			}
 		};
 	}

+ 101 - 100
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();

+ 2 - 2
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;
 }

+ 42 - 39
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()

+ 2 - 0
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);

+ 42 - 46
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++)
 	{

+ 60 - 12
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;

+ 75 - 40
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<uint16>
 {
 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) \

+ 1 - 1
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"]
 

+ 8 - 0
IDE/Tests/Tiny/BeefProj.toml

@@ -0,0 +1,8 @@
+FileVersion = 1
+
+[Project]
+Name = "Tiny"
+StartupObject = "Tiny.Program"
+
+[Configs.Release.Win64]
+CLibType = "SystemMSVCRT"

+ 26 - 0
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"

+ 13 - 0
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;
+	}
+}

+ 14 - 8
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)]

+ 8 - 1
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)]

+ 131 - 67
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
+		}
+
+#if BF_ENABLE_OBJECT_DEBUG_FLAGS
+		[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();
 
-        int IHashable.GetHashCode()
+		public Type GetType()
         {
-            return (int)(void*)this;
+			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;
         }
 
-        public Type GetType()
+        TypeId GetTypeId()
         {
-            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            
-            if ((type.[Friend]mTypeFlags & TypeFlags.Boxed) != 0)
-            {
-                //int32 underlyingType = (int32)((TypeInstance)type).mUnderlyingType;
-                type = Type.[Friend]GetType(((TypeInstance)type).[Friend]mUnderlyingType);
-            }
-            return type;
+            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>
     {
         T GetBaseResult();
     }
-        
+
     struct ValueType
     {
 		public static extern bool Equals<T>(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<T> Parse<T>(String str) where T : Enum
@@ -528,7 +592,7 @@ namespace System
     {
 		public int64 mMethodId;
         public DeferredCall* mNext;
-        
+
 		public void Cancel() mut
 		{
 			mMethodId = 0;

+ 5 - 1
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;

+ 5 - 3
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;

+ 9 - 3
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 ");

+ 7 - 0
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,

+ 6 - 1
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";

+ 8 - 0
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);

+ 7 - 0
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)

+ 26 - 1
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>("RuntimeKind");
+					options.mReflectKind = data.GetEnum<ReflectKind>("ReflectKind");
 					options.mInitLocalVariables = data.GetBool("InitLocalVariables", false);
                     options.mRuntimeChecks = data.GetBool("RuntimeChecks", !isRelease);
                     options.mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck", !isRelease);

+ 14 - 0
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);
 			}

+ 2 - 0
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");

+ 8 - 4
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, &sectionSize);
@@ -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;
 }

+ 77 - 18
IDEHelper/Compiler/BfCompiler.cpp

@@ -1220,7 +1220,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule)
 
 	Array<BfType*> vdataTypeList;
 	HashSet<BfModule*> usedModuleSet;
-	HashSet<BfType*> reflectTypeSet;
+	HashSet<BfType*> reflectSkipTypeSet;
 	HashSet<BfType*> 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<int, int> 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<BfType*> 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<BfType*> vDataTypeSet;
 	SmallVector<BfIRValue, 256> typeDataVector;
+	Array<BfType*> 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;
-			}
+			}*/
+
+			if (needsVData)
+				vDataTypeSet.Add(type);
 
-			typeVariable = bfModule->CreateTypeData(type, usedStringIdMap, forceReflectFields, needsTypeData, needsTypeNames, needsVData);
+			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<BfIRValue> 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<BfGenericInstanceTypeRef>(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");

+ 2 - 0
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();

+ 92 - 37
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;
 				}
-			}
 
-			workIdx = mPopulateTypeWorkList.RemoveAt(workIdx);
+				// We want to resolve type aliases first, allowing possible mMidCompileWorkList entries
+				int wantPass = type->IsTypeAlias() ? 0 : 1;
+				if (populatePass != wantPass)
+					continue;
 
-			if (rebuildType)
-				RebuildType(type);
+				auto typeInst = type->ToTypeInstance();
+				if ((typeInst != NULL) && (resolveParser != NULL))
+				{
+					if (!typeInst->mTypeDef->GetLatest()->HasSource(resolveParser))
+					{
+						continue;
+					}
+				}
 
-			BF_ASSERT(this == type->mContext);
-			auto useModule = type->GetModule();
-			if (useModule == NULL)
-			{
-				if (mCompiler->mOptions.mCompileOnDemandKind == BfCompileOnDemandKind_AlwaysInclude)
-					useModule = mScratchModule;
-				else
-					useModule = mUnreifiedModule;
+				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 (!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())
 	{

+ 1 - 0
IDEHelper/Compiler/BfContext.h

@@ -382,6 +382,7 @@ public:
 	BfModule* mScratchModule;
 	BfModule* mUnreifiedModule;
 	HashSet<String> mUsedModuleNames;
+	HashSet<BfType*> mGhostDependencies; // We couldn't properly rebuild our dependencies
 	Dictionary<BfProject*, BfModule*> mProjectModule;
 	Array<BfModule*> mModules;
 	Array<BfModule*> mDeletingModules;

+ 32 - 6
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);
 				}
 			}

+ 130 - 48
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<int, int>& 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<int, int>& 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<int, int>& 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<int, int>& 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<int, int>& 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<BfIRValue, 1> extVTableData;
 
@@ -6752,6 +6764,9 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& 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<int, int>& 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<int, int>& 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<int, int>& usedStrin
 	BfIRType interfaceDataPtrType = mBfIRBuilder->GetPointerTo(mBfIRBuilder->MapType(reflectInterfaceDataType));
 	Array<bool> 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<int, int>& 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<BfTypeState*> 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<BfVarTypeReference>()))
@@ -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();

+ 11 - 3
IDEHelper/Compiler/BfModule.h

@@ -158,6 +158,12 @@ enum BfLocalVarAssignKind : int8
 	BfLocalVarAssignKind_Unconditional = 2
 };
 
+struct BfCreateTypeDataContext
+{
+	Dictionary<int, int> mUsedStringIdMap;
+	HashSet<BfTypeInstance*> 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<BfAstNode*>* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
 	BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray<BfAstNode*>* 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<uint8>& data, Dictionary<int, int>& usedStringIdMap);
 	BfIRValue CreateFieldData(BfFieldInstance* fieldInstance, int customAttrIdx);
-	BfIRValue CreateTypeData(BfType* type, Dictionary<int, int>& 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:

+ 31 - 8
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -410,7 +410,7 @@ bool BfModule::ValidateGenericConstraints(BfAstNode* typeRef, BfTypeInstance* ge
 	SetAndRestoreValue<bool> 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<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
 	SetAndRestoreValue<BfMethodState*> 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<BfGenericInstanceTypeRef>(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<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, result->ToTypeInstance());

+ 8 - 5
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<BfIRType>& 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;
 

+ 10 - 4
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 (getNextMethodInst)
+		{
+			nextResult = BfTypedValue(CreateAlloca(getNextMethodInst.mMethodInstance->mReturnType), getNextMethodInst.mMethodInstance->mReturnType, true);
 
-		if (nextResult.mType->IsGenericTypeInstance())
+			if (nextResult.mType->IsGenericTypeInstance())
+			{
+				nextEmbeddedType = ((BfTypeInstance*)nextResult.mType)->mGenericTypeInfo->mTypeGenericArguments[0];
+			}
+		}
+		else
 		{
-			nextEmbeddedType = ((BfTypeInstance*)nextResult.mType)->mGenericTypeInfo->mTypeGenericArguments[0];
+			InternalError("Failed to find GetNext");
 		}
 	}
 	if (nextEmbeddedType == NULL)

+ 2 - 2
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<int, int> 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))

+ 9 - 3
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<PESectionHeader> sectionHeaders;
 	sectionHeaders.Resize(ntHdr.mFileHeader.mNumberOfSections);
-	mSectionRVAs.Resize(sectionHeaders.size() + 1);
+	mSectionHeaders.Resize(sectionHeaders.size() + 1);
 
 	Array<String> 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] != '.'))

+ 4 - 1
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<DbgSrcFile*> mSrcFileDeferredRefs;
-	Array<addr_target> mSectionRVAs;
+	Array<PESectionHeader> mSectionHeaders;
 	SLIList<DbgSymbol*> mDeferredSymbols;
 	Beefy::OwnedVector<DbgDeferredHotResolve> mDeferredHotResolveList;
 	Array<DbgHotTargetSection*> mHotTargetSections;

+ 7 - 0
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();

+ 1 - 0
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;

+ 58 - 12
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<addr_target>(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<int32>(classVDataAddr);
+					addr_target arrayAddr = mBfTypesInfoAddr + typeId * sizeof(addr_target);
+					addr_target typeAddr = mDebugger->ReadMemory<addr_target>(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;
 

+ 1 - 0
IDEHelper/HotScanner.h

@@ -84,6 +84,7 @@ class DbgHotScanner
 public:
 	WinDebugger* mDebugger;
 	DbgGCData mDbgGCData;
+	addr_target mBfTypesInfoAddr;
 	Beefy::Dictionary<addr_target, int> mFoundClassVDataAddrs;
 	Beefy::Dictionary<addr_target, int> mFoundRawAllocDataAddrs;
 	Beefy::Dictionary<addr_target, int> mFoundTypeAddrs;

+ 3 - 0
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"

+ 204 - 0
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<CvModuleInfo*> 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<DbgCompileUnitContrib*> 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<SymbolEntry> 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<DbgSubprogram*> 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);

+ 1 - 0
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;

+ 14 - 1
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