diff --git a/BeefBoot/BootApp.cpp b/BeefBoot/BootApp.cpp index c7e420de..9f60e9b7 100644 --- a/BeefBoot/BootApp.cpp +++ b/BeefBoot/BootApp.cpp @@ -47,7 +47,7 @@ BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem); BF_IMPORT void BF_CALLTYPE BfSystem_Delete(void* bfSystem); BF_IMPORT void* BF_CALLTYPE BfSystem_CreatePassInstance(void* bfSystem); BF_IMPORT void* BF_CALLTYPE BfSystem_CreateCompiler(void* bfSystem, bool isResolveOnly); -BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName); +BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName, const char* projectDir); BF_IMPORT void BF_CALLTYPE BfParser_Delete(void* bfParser); BF_IMPORT void BF_CALLTYPE BfSystem_AddTypeOptions(void* bfSystem, const char* filter, int32 simdSetting, int32 optimizationLevel, int32 emitDebugInfo, int32 arrayBoundsCheck, int32 initLocalVariables, int32 emitDynamicCastCheck, int32 emitObjectAccessCheck, int32 allocStackTraceDepth); @@ -790,12 +790,12 @@ bool BootApp::Compile() projectName.RemoveToEnd(dotPos); if (projectName.IsEmpty()) projectName.Append("BeefProject"); - - mProject = BfSystem_CreateProject(mSystem, projectName.c_str()); + + mProject = BfSystem_CreateProject(mSystem, projectName.c_str(), GetFileDir(mTargetPath).c_str()); if (mIsCERun) { - mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib"); + mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib", GetFileDir(mTargetPath).c_str()); BfProjectFlags flags = BfProjectFlags_None; BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, 0, 0, flags); diff --git a/BeefLibs/Beefy2D/src/sys/SysMenu.bf b/BeefLibs/Beefy2D/src/sys/SysMenu.bf index 4dc7cda1..a125a554 100644 --- a/BeefLibs/Beefy2D/src/sys/SysMenu.bf +++ b/BeefLibs/Beefy2D/src/sys/SysMenu.bf @@ -69,6 +69,12 @@ namespace Beefy.sys Modify(mText, mHotKey, mBitmap, mEnabled, mCheckState, mRadioCheck); } + public void SetCheckState(int32 checkState) + { + mCheckState = checkState; + Modify(mText, mHotKey, mBitmap, mEnabled, mCheckState, mRadioCheck); + } + public void SetHotKey(StringView hotKey) { if (hotKey.IsNull) diff --git a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf index cf92c840..7267ce07 100644 --- a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf @@ -2366,7 +2366,14 @@ namespace Beefy.widgets case KeyCode.Down: { int32 aDir = (keyCode == KeyCode.Up) ? -1 : 1; - bool didSelectionMove = PrepareForCursorMove(aDir); + if ((HasSelection()) && (!mWidgetWindow.IsKeyDown(KeyCode.Shift))) + { + var lineAndCol = CursorLineAndColumn; + var usePos = (aDir < 0) ? (int32)mSelection.Value.MinPos : mSelection.Value.MaxPos; + GetLineCharAtIdx(usePos, var selLine, var selLineChar); + CursorLineAndColumn = .(selLine, lineAndCol.mColumn); + mSelection = null; + } GetCursorLineChar(out lineIdx, out lineChar); @@ -2403,9 +2410,6 @@ namespace Beefy.widgets mCursorWantX = wantedX; } - - if (didSelectionMove) - CursorToLineStart(false); } break; case KeyCode.Home: diff --git a/BeefLibs/Beefy2D/src/widgets/IMenu.bf b/BeefLibs/Beefy2D/src/widgets/IMenu.bf index a2174048..5156ffbf 100644 --- a/BeefLibs/Beefy2D/src/widgets/IMenu.bf +++ b/BeefLibs/Beefy2D/src/widgets/IMenu.bf @@ -10,6 +10,7 @@ namespace Beefy.widgets public interface IMenu { void SetDisabled(bool enable); + void SetCheckState(int32 checkState); } public interface IMenuContainer diff --git a/BeefLibs/Beefy2D/src/widgets/KeyCode.bf b/BeefLibs/Beefy2D/src/widgets/KeyCode.bf index 74c32e7d..00e1f9f0 100644 --- a/BeefLibs/Beefy2D/src/widgets/KeyCode.bf +++ b/BeefLibs/Beefy2D/src/widgets/KeyCode.bf @@ -90,13 +90,13 @@ namespace Beefy.widgets Minus = 0xBD, Period = 0xBE, Slash = 0xBF, + Tilde = 0xC0, Grave = 0xC0, LBracket = 0xDB, Backslash = 0xDC, RBracket = 0xDD, Apostrophe = 0xDE, Backtick = 0xDF, - Tilde = 0xC0, Command = 0xF0, COUNT = 0xFF, @@ -141,6 +141,16 @@ namespace Beefy.widgets return (KeyCode)LBracket; if (c == ']') return (KeyCode)RBracket; + if (c == '/') + return (KeyCode)Slash; + if (c == '\\') + return (KeyCode)Backslash; + if (c == '`') + return (KeyCode)Tilde; + if (c == '.') + return (KeyCode)Period; + if (c == ',') + return (KeyCode)Comma; } if (str.StartsWith("0x")) @@ -168,6 +178,10 @@ namespace Beefy.widgets c = '['; case RBracket: c = ']'; + case .Slash: + c = '/'; + case .Backslash: + c = '\\'; default: } if (c != 0) diff --git a/BeefLibs/Beefy2D/src/widgets/Menu.bf b/BeefLibs/Beefy2D/src/widgets/Menu.bf index dd6adfc5..2cfdf1dc 100644 --- a/BeefLibs/Beefy2D/src/widgets/Menu.bf +++ b/BeefLibs/Beefy2D/src/widgets/Menu.bf @@ -616,5 +616,10 @@ namespace Beefy.widgets { mDisabled = disabled; } + + public void SetCheckState(int32 checkState) + { + + } } } diff --git a/BeefLibs/SDL2/src/SDLApp.bf b/BeefLibs/SDL2/src/SDLApp.bf index 90026bbd..14a8eadd 100644 --- a/BeefLibs/SDL2/src/SDLApp.bf +++ b/BeefLibs/SDL2/src/SDLApp.bf @@ -117,7 +117,7 @@ namespace SDL2 SDL.EventState(.JoyDeviceAdded, .Disable); SDL.EventState(.JoyDeviceRemoved, .Disable); - mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Shown); + mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Hidden); // Initially hide window mRenderer = SDL.CreateRenderer(mWindow, -1, .Accelerated); mScreen = SDL.GetWindowSurface(mWindow); SDLImage.Init(.PNG | .JPG); @@ -246,7 +246,9 @@ namespace SDL2 if (curPhysTickCount == 0) { // Initial render - Render(); + Render(); + // Show initially hidden window, mitigates white flash on slow startups + SDL.ShowWindow(mWindow); } else { diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index 3a16088d..8549c43c 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -30,6 +30,8 @@ namespace System Delete = 0x80000, Alias = 0x100000, Block = 0x200000, + DelegateTypeRef = 0x400000, + FunctionTypeRef = 0x800000, Types = .Struct | .Enum | .Function | .Class | .Interface, ValueTypes = .Struct | .Enum | .Function, @@ -227,7 +229,7 @@ namespace System } - [AttributeUsage(.Method | .Constructor | .Delegate | .Function)] + [AttributeUsage(.Method | .Constructor | .Delegate | .Function | .DelegateTypeRef | .FunctionTypeRef)] public struct CallingConventionAttribute : Attribute { public enum Kind diff --git a/BeefLibs/corlib/src/Boolean.bf b/BeefLibs/corlib/src/Boolean.bf index 57b6be83..deaf0e09 100644 --- a/BeefLibs/corlib/src/Boolean.bf +++ b/BeefLibs/corlib/src/Boolean.bf @@ -17,6 +17,11 @@ namespace System strBuffer.Append(((bool)this) ? TrueString : FalseString); } + public static int operator<=>(Boolean a, Boolean b) + { + return (SelfBase)a <=> (SelfBase)b; + } + public int GetHashCode() { return ((bool)this) ? 1 : 0; diff --git a/BeefLibs/corlib/src/Collections/Dictionary.bf b/BeefLibs/corlib/src/Collections/Dictionary.bf index 1aaa7ccf..83219754 100644 --- a/BeefLibs/corlib/src/Collections/Dictionary.bf +++ b/BeefLibs/corlib/src/Collections/Dictionary.bf @@ -311,6 +311,7 @@ namespace System.Collections { if (sizeof(int) == 4) return (int32)hashCode & 0x7FFFFFFF; +#unwarn if (sizeof(int_cosize) == 8) return (int_cosize)(hashCode & 0x7FFFFFFF'FFFFFFFFL); return ((int32)hashCode ^ (int32)((int64)hashCode >> 33)) & 0x7FFFFFFF; diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index 3030c444..290c821a 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -2,6 +2,7 @@ using System.Reflection; using System.Diagnostics; using System.Collections; using System.Security.Cryptography; +using System.IO; namespace System { @@ -217,6 +218,12 @@ namespace System [LinkName("#CallerFileDir")] public static extern String CallerFileDir; + [LinkName("#CallerType")] + public static extern Type CallerType; + + [LinkName("#CallerTypeName")] + public static extern String CallerTypeName; + [LinkName("#CallerMemberName")] public static extern String CallerMemberName; @@ -300,5 +307,21 @@ namespace System if (Compiler.IsComptime) Comptime_EmitMixin(text); } + + [Comptime] + public static Span ReadBinary(StringView path) + { + List data = scope .(); + File.ReadAll(path, data); + return data; + } + + [Comptime] + public static String ReadText(StringView path) + { + String data = scope .(); + File.ReadAllText(path, data); + return data; + } } } diff --git a/BeefLibs/corlib/src/Diagnostics/Debug.bf b/BeefLibs/corlib/src/Diagnostics/Debug.bf index e7a2a554..7ab33151 100644 --- a/BeefLibs/corlib/src/Diagnostics/Debug.bf +++ b/BeefLibs/corlib/src/Diagnostics/Debug.bf @@ -106,5 +106,24 @@ namespace System.Diagnostics if (gIsDebuggerPresent) Break(); } + + public static void WriteMemory(Span mem) + { + String str = scope .(); + for (int i < mem.Length) + { + if ((i != 0) && (i % 16 == 0)) + str.Append('\n'); + str.AppendF($" {mem.[Friend]mPtr[i]:X2}"); + } + str.Append('\n'); + Write(str); + } + + public static void WriteMemory(T result) + { +#unwarn + WriteMemory(.((.)&result, sizeof(T))); + } } } diff --git a/BeefLibs/corlib/src/Diagnostics/Profiler.bf b/BeefLibs/corlib/src/Diagnostics/Profiler.bf index f9fdbf54..f221cd70 100644 --- a/BeefLibs/corlib/src/Diagnostics/Profiler.bf +++ b/BeefLibs/corlib/src/Diagnostics/Profiler.bf @@ -10,12 +10,23 @@ namespace System.Diagnostics struct ProfileInstance : int32 { - public void Dispose() + public bool HasValue { + get + { + return this != 0; + } + } + + public void Dispose() mut + { + if (this == 0) + return; String str = scope String(); str.Append("StopSampling\t"); ((int32)this).ToString(str); Internal.ProfilerCmd(str); + this = 0; } } diff --git a/BeefLibs/corlib/src/Enum.bf b/BeefLibs/corlib/src/Enum.bf index f39872e1..31481a55 100644 --- a/BeefLibs/corlib/src/Enum.bf +++ b/BeefLibs/corlib/src/Enum.bf @@ -1,4 +1,5 @@ using System.Reflection; +using System.Collections; namespace System { @@ -30,12 +31,157 @@ namespace System return .Err; } - /*public override void ToString(String strBuffer) mut + public static bool IsDefined(T value) + where T : enum { - Type type = GetType(); - int32* iPtr = (int32*)((int)(&this) + (int)type.Size); - EnumToString(type, strBuffer, *iPtr); - //EnumToString(GetType(), ) - }*/ + var typeInst = (TypeInstance)typeof(T); + for (var field in typeInst.GetFields()) + { + if (field.[Friend]mFieldData.[Friend]mData == (.)value) + return true; + } + + return false; + } + + public static EnumEnumerator GetEnumerator() + where TEnum : enum + { + return .(); + } + + public static EnumValuesEnumerator GetValues() + where TEnum : enum + { + return .(); + } + + public static EnumNamesEnumerator GetNames() + where TEnum : enum + { + return .(); + } + + private struct EnumFieldsEnumerator + where TEnum : enum + { + TypeInstance mTypeInstance; + int32 mIdx; + + public this() + { + mTypeInstance = typeof(TEnum) as TypeInstance; + mIdx = -1; + } + + public void Reset() mut + { + mIdx = -1; + } + + public void Dispose() + { + } + + public bool MoveNext() mut + { + if (mTypeInstance == null) + return false; + + TypeInstance.FieldData* fieldData = null; + + repeat + { + mIdx++; + if (mIdx == mTypeInstance.[Friend]mFieldDataCount) + return false; + fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; + } + while (!fieldData.mFlags.HasFlag(.EnumCase)); + + return true; + } + + public FieldInfo Current + { + get + { + var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; + return FieldInfo(mTypeInstance, fieldData); + } + } + + public int32 Index + { + get + { + return mIdx; + } + } + + public Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + + public struct EnumEnumerator : EnumFieldsEnumerator, IEnumerator<(StringView name, TEnum value)> + where TEnum : enum + { + public new (StringView name, TEnum value) Current + { + get + { + return ((.)base.Current.[Friend]mFieldData.[Friend]mName, (.)base.Current.[Friend]mFieldData.[Friend]mData); + } + } + + public new Result<(StringView name, TEnum value)> GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + + public struct EnumValuesEnumerator : EnumFieldsEnumerator, IEnumerator + where TEnum : enum + { + public new TEnum Current + { + get + { + return (.)base.Current.[Friend]mFieldData.[Friend]mData; + } + } + + public new Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + + public struct EnumNamesEnumerator : EnumFieldsEnumerator, IEnumerator + where TEnum : enum + { + public new StringView Current + { + get + { + return (.)base.Current.[Friend]mFieldData.[Friend]mName; + } + } + + public new Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } } } diff --git a/BeefLibs/corlib/src/IO/Shell.bf b/BeefLibs/corlib/src/IO/Shell.bf index 1c230313..41151db2 100644 --- a/BeefLibs/corlib/src/IO/Shell.bf +++ b/BeefLibs/corlib/src/IO/Shell.bf @@ -9,7 +9,7 @@ namespace System.IO { public struct VTable : COM_IUnknown.VTable { - public function HResult(COM_IPersistFile* self, Guid* pClassID) GetClassID; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, Guid* pClassID) GetClassID; } } @@ -19,11 +19,11 @@ namespace System.IO public struct VTable : COM_IPersist.VTable { - public function HResult(COM_IPersistFile* self) IsDirty; - public function HResult(COM_IPersistFile* self, char16* pszFileName) Load; - public function HResult(COM_IPersistFile* self, char16* pszFileName, Windows.IntBool remember) Save; - public function HResult(COM_IPersistFile* self, char16* pszFileName) SaveCompleted; - public function HResult(COM_IPersistFile* self, char16* pszName) GetCurFile; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self) IsDirty; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName) Load; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName, Windows.IntBool remember) Save; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName) SaveCompleted; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszName) GetCurFile; } public new VTable* VT { @@ -43,24 +43,24 @@ namespace System.IO public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellLink* self, char16* pszFile, int32 cch, Windows.NativeFindData* pfd, uint32 fFlags) GetPath; - public function HResult(COM_IShellLink* self, IDLIST** ppidl) GetIDList; - public function HResult(COM_IShellLink* self, IDLIST* pidl) SetIDList; - public function HResult(COM_IShellLink* self, char16* pszName, int32 cch) GetDescription; - public function HResult(COM_IShellLink* self, char16* pszName) SetDescription; - public function HResult(COM_IShellLink* self, char16* pszDir, int32 cch) GetWorkingDirectory; - public function HResult(COM_IShellLink* self, char16* pszDir) SetWorkingDirectory; - public function HResult(COM_IShellLink* self, char16* pszArgs, int32 cch) GetArguments; - public function HResult(COM_IShellLink* self, char16* pszArgs) SetArguments; - public function HResult(COM_IShellLink* self, uint16 *pwHotkey) GetHotkey; - public function HResult(COM_IShellLink* self, uint16 wHotkey) SetHotkey; - public function HResult(COM_IShellLink* self, int32 *piShowCmd) GetShowCmd; - public function HResult(COM_IShellLink* self, int32 iShowCmd) SetShowCmd; - public function HResult(COM_IShellLink* self, char16* pszIconPath, int32 cch, int32 *piIcon) GetIconLocation; - public function HResult(COM_IShellLink* self, char16* pszIconPath, int32 iIcon) SetIconLocation; - public function HResult(COM_IShellLink* self, char16* pszPathRel, uint32 dwReserved) SetRelativePath; - public function HResult(COM_IShellLink* self, Windows.HWnd hwnd, uint32 fFlags) Resolve; - public function HResult(COM_IShellLink* self, char16* pszFile) SetPath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszFile, int32 cch, Windows.NativeFindData* pfd, uint32 fFlags) GetPath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, IDLIST** ppidl) GetIDList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, IDLIST* pidl) SetIDList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszName, int32 cch) GetDescription; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszName) SetDescription; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszDir, int32 cch) GetWorkingDirectory; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszDir) SetWorkingDirectory; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszArgs, int32 cch) GetArguments; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszArgs) SetArguments; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, uint16 *pwHotkey) GetHotkey; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, uint16 wHotkey) SetHotkey; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, int32 *piShowCmd) GetShowCmd; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, int32 iShowCmd) SetShowCmd; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszIconPath, int32 cch, int32 *piIcon) GetIconLocation; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszIconPath, int32 iIcon) SetIconLocation; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszPathRel, uint32 dwReserved) SetRelativePath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, Windows.HWnd hwnd, uint32 fFlags) Resolve; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszFile) SetPath; } public new VTable* VT diff --git a/BeefLibs/corlib/src/OperatingSystem.bf b/BeefLibs/corlib/src/OperatingSystem.bf index eb1d578b..117c6819 100644 --- a/BeefLibs/corlib/src/OperatingSystem.bf +++ b/BeefLibs/corlib/src/OperatingSystem.bf @@ -118,6 +118,9 @@ namespace System public this() { + if (Compiler.IsComptime) + return; + #if BF_PLATFORM_WINDOWS bool isWinSrv() { diff --git a/BeefLibs/corlib/src/Reflection/AttributeInfo.bf b/BeefLibs/corlib/src/Reflection/AttributeInfo.bf index 1e515ae9..0489904a 100644 --- a/BeefLibs/corlib/src/Reflection/AttributeInfo.bf +++ b/BeefLibs/corlib/src/Reflection/AttributeInfo.bf @@ -105,7 +105,8 @@ namespace System.Reflection argIdx++; } - methodInfo.Invoke(targetAttr, params args); + if (methodInfo.Invoke(targetAttr, params args) case .Ok(var val)) + val.Dispose(); return .Ok; } diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 70fc7b5b..25bc0c8d 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -72,7 +72,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } @@ -82,7 +82,7 @@ namespace System { let bufferSize = 16 - sizeof(char8*); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } @@ -93,7 +93,7 @@ namespace System let count = str.mLength; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); Internal.MemCpy(Ptr, str.Ptr, count); mLength = count; mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); @@ -106,7 +106,7 @@ namespace System let count = str.mLength - offset; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = str.Ptr; for (int_strsize i = 0; i < count; i++) @@ -123,7 +123,7 @@ namespace System int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = str.Ptr; for (int i = 0; i < count; i++) @@ -137,7 +137,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int_strsize i = 0; i < count; i++) ptr[i] = c; @@ -151,7 +151,7 @@ namespace System let count = Internal.CStrLen(char8Ptr); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int_strsize i = 0; i < count; i++) ptr[i] = char8Ptr[i]; @@ -164,7 +164,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int i = 0; i < count; i++) ptr[i] = char8Ptr[i]; @@ -178,7 +178,7 @@ namespace System let count = UTF16.GetLengthAsUTF8(char16Ptr); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; UTF16.Decode(char16Ptr, this); @@ -190,7 +190,7 @@ namespace System let count = UTF16.GetLengthAsUTF8(chars); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; UTF16.Decode(chars, this); @@ -202,7 +202,7 @@ namespace System let tryBufferSize = strView.Length - sizeof(char8*); let bufferSize = (tryBufferSize >= 0) ? tryBufferSize : 0; #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; Internal.MemCpy(ptr, strView.Ptr, strView.Length); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); @@ -215,7 +215,7 @@ namespace System let count = strView.Length + (flags.HasFlag(.NullTerminate) ? 1 : 0); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; Internal.MemCpy(ptr, strView.Ptr, strView.Length); if (flags.HasFlag(.NullTerminate)) @@ -232,7 +232,7 @@ namespace System let count = strView.Length - offset; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = strView.Ptr; for (int i = 0; i < count; i++) @@ -249,7 +249,7 @@ namespace System int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = strView.Ptr; for (int i = 0; i < count; i++) @@ -263,7 +263,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int i = 0; i < count; i++) ptr[i] = chars[i + offset]; @@ -285,7 +285,7 @@ namespace System int count = StrLengths(strs); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; int curIdx = 0; for (var str in strs) @@ -1965,6 +1965,22 @@ namespace System return EqualsIgnoreCaseHelper(a.Ptr, b.Ptr, a.mLength); return EqualsHelper(a.Ptr, b.Ptr, a.mLength); } + + public bool Equals(StringView str) + { + if (mLength != str.[Friend]mLength) + return false; + return EqualsHelper(str.Ptr, mPtr, mLength); + } + + public bool Equals(StringView str, StringComparison comparisonType = StringComparison.Ordinal) + { + if (mLength != str.[Friend]mLength) + return false; + if (comparisonType == StringComparison.OrdinalIgnoreCase) + return EqualsIgnoreCaseHelper(str.Ptr, mPtr, mLength); + return EqualsHelper(str.Ptr, mPtr, mLength); + } public bool StartsWith(StringView b, StringComparison comparisonType = StringComparison.Ordinal) { @@ -2278,6 +2294,36 @@ namespace System TrimStart((.)trimChar); TrimEnd((.)trimChar); } + + public void PadLeft(int totalWidth, char8 paddingChar) + { + Insert(0, paddingChar, totalWidth - Length); + } + + public void PadLeft(int totalWidth, char32 paddingChar) + { + Insert(0, paddingChar, totalWidth - Length); + } + + public void PadLeft(int totalWidth) + { + Insert(0, ' ', totalWidth - Length); + } + + public void PadRight(int totalWidth, char8 paddingChar) + { + Append(paddingChar, totalWidth - Length); + } + + public void PadRight(int totalWidth, char32 paddingChar) + { + Append(paddingChar, totalWidth - Length); + } + + public void PadRight(int totalWidth) + { + Append(' ', totalWidth - Length); + } public void Join(StringView sep, IEnumerator enumerable) { diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 1f79729b..89bcb9c4 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -1250,7 +1250,8 @@ namespace System.Reflection Const = 0x0040, // Value is compile time constant. SpecialName = 0x0080, // field is special. Name describes how. EnumPayload = 0x0100, - EnumDiscriminator = 0x0200 + EnumDiscriminator = 0x0200, + EnumCase = 0x0400 } public enum MethodFlags : uint16 diff --git a/BeefLibs/corlib/src/Variant.bf b/BeefLibs/corlib/src/Variant.bf index 5c736df6..825b5f96 100644 --- a/BeefLibs/corlib/src/Variant.bf +++ b/BeefLibs/corlib/src/Variant.bf @@ -2,7 +2,7 @@ using System.Diagnostics; namespace System { - struct Variant + struct Variant : IDisposable { enum ObjectType { @@ -472,4 +472,4 @@ namespace System return variant; } } -} \ No newline at end of file +} diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index 23de97ad..7a3a135c 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -47,9 +47,9 @@ namespace System public struct VTable { - public function HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface; - public function uint32(COM_IUnknown* self) AddRef; - public function uint32(COM_IUnknown* self) Release; + public function [CallingConvention(.Stdcall)] HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface; + public function [CallingConvention(.Stdcall)] uint32(COM_IUnknown* self) AddRef; + public function [CallingConvention(.Stdcall)] uint32(COM_IUnknown* self) Release; } public enum HResult : int32 @@ -1124,14 +1124,13 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; - + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; } } @@ -1154,12 +1153,11 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; - public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; - public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; - public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; - + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; } public new VTable* VT { @@ -1207,13 +1205,13 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; - public function HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; - public function HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; - public function HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; - public function HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; - public function HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; } public new VTable* VT { @@ -1268,30 +1266,30 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; - public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; - public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; - public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; - public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; - public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; - public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; - public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; - public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; - public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; - public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; - public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; - public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; - public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; - public function HResult(COM_IFileDialog* self, int hr) Close; - public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; - public function HResult(COM_IFileDialog* self) ClearClientData; - public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, FOS fos) SetOptions; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszName) SetFileName; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, int hr) Close; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self) ClearClientData; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, void* pFilter) SetFilter; } public new VTable* VT { @@ -1314,8 +1312,8 @@ namespace System public struct VTable : COM_IFileDialog.VTable { - public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; - public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; } public new VTable* VT { diff --git a/BeefTools/BeefPerf/src/BPApp.bf b/BeefTools/BeefPerf/src/BPApp.bf index 730ec048..fffe1822 100644 --- a/BeefTools/BeefPerf/src/BPApp.bf +++ b/BeefTools/BeefPerf/src/BPApp.bf @@ -505,7 +505,7 @@ namespace BeefPerf subMenu = root.AddMenuItem("&Debug"); subMenu.AddMenuItem("GC Collect", null, new (menu) => { - if (Profiler.StartSampling() case .Ok(let id)) + if (Profiler.StartSampling() case .Ok(var id)) { GC.Collect(); id.Dispose(); diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index e8a91d1e..9ba9e69b 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -2909,6 +2909,12 @@ BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr //TODO: this doesn't set file stream location. It only works for streams like pipes, sockets, etc if (::ReadFileEx(file->mHandle, buffer, (uint32)size, &overlapped, OverlappedReadComplete)) { + if (file->mAsyncData == NULL) + { + OUTRESULT(BfpFileResult_InvalidParameter); + return 0; + } + if (!file->mAsyncData->WaitAndResetEvent(timeoutMS)) { ::CancelIoEx(file->mHandle, &overlapped); diff --git a/BeefySysLib/util/String.h b/BeefySysLib/util/String.h index 3d7d8299..e30d9679 100644 --- a/BeefySysLib/util/String.h +++ b/BeefySysLib/util/String.h @@ -622,7 +622,17 @@ public: str.mLength = (int_strsize)strlen(charPtr); str.mAllocSizeAndFlags = str.mLength | StrPtrFlag; return str; - } + } + + static StringImpl MakeRef(const char* charPtr, intptr length) + { + StringImpl str; + // This is just a ref - called when we pass a literal to a method (for example) + str.mPtr = (char*)charPtr; + str.mLength = (int_strsize)length; + str.mAllocSizeAndFlags = str.mLength | StrPtrFlag; + return str; + } static StringImpl MakeRef(const StringView& strView) { diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index f0b2de76..c3422655 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -9,7 +9,7 @@ namespace IDE { public KeyCode mKeyCode; public KeyFlags mKeyFlags; - + public int GetHashCode() { return (int)mKeyCode | (int)mKeyFlags << 16; @@ -121,10 +121,21 @@ namespace IDE class CommandMap : IDECommandBase { public Dictionary mMap = new .() ~ delete _; + public List mFailValues ~ delete _; + + public List FailValues + { + get + { + if (mFailValues == null) + mFailValues = new .(); + return mFailValues; + } + } public void Clear() { - for (let val in mMap.Values) + void Release(IDECommandBase val) { if (var cmdMap = val as CommandMap) delete cmdMap; @@ -136,6 +147,15 @@ namespace IDE ideCommand.mNext = null; } } + + for (let val in mMap.Values) + Release(val); + if (mFailValues != null) + { + for (var val in mFailValues) + Release(val); + mFailValues.Clear(); + } mMap.Clear(); } @@ -194,7 +214,9 @@ namespace IDE Add("Close Document", new () => { gApp.[Friend]TryCloseCurrentDocument(); }); Add("Close Panel", new () => { gApp.[Friend]TryCloseCurrentPanel(); }); Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew); - Add("Comment Selection", new => gApp.[Friend]CommentSelection); + Add("Comment Block", new => gApp.[Friend]CommentBlock, .Editor); + Add("Comment Lines", new => gApp.[Friend]CommentLines, .Editor); + Add("Comment Toggle", new => gApp.[Friend]CommentToggle, .Editor); Add("Compile File", new => gApp.Cmd_CompileFile); Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true, true); }); Add("Debug Normal Tests", new () => { gApp.[Friend]RunTests(false, true); }); @@ -251,6 +273,7 @@ namespace IDE Add("Run Normal Tests", new () => { gApp.[Friend]RunTests(false, false); }); Add("Run To Cursor", new => gApp.[Friend]RunToCursor); Add("Run Without Compiling", new => gApp.[Friend]RunWithoutCompiling); + Add("Safe Mode Toggle", new () => { gApp.SafeModeToggle(); }); Add("Save All", new () => { gApp.SaveAll(); }); Add("Save As", new () => { gApp.SaveAs(); }); Add("Save File", new => gApp.SaveFile); diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index efc60b19..4933ef06 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -76,6 +76,9 @@ namespace IDE.Compiler [CallingConvention(.Stdcall), CLink] static extern int32 BfCompiler_GetCurConstEvalExecuteId(void* bfCompiler); + [CallingConvention(.Stdcall), CLink] + static extern bool BfCompiler_GetLastHadComptimeRebuilds(void* bfCompiler); + [CallingConvention(.Stdcall), CLink] static extern void BfCompiler_Delete(void* bfCompiler); @@ -834,5 +837,10 @@ namespace IDE.Compiler } } } + + public bool GetLastHadComptimeRebuilds() + { + return BfCompiler_GetLastHadComptimeRebuilds(mNativeBfCompiler); + } } } diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 6f0c0106..5bf14ae8 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -78,8 +78,9 @@ namespace IDE.Compiler public bool mCancelled; public int32 mTextVersion = -1; public bool mIsUserRequested; - public bool mDoFuzzyAutoComplete; + public Stopwatch mStopwatch ~ delete _; + public ProfileInstance mProfileInstance ~ _.Dispose(); } public class BfParser : ILeakIdentifiable @@ -122,7 +123,7 @@ namespace IDE.Compiler static extern bool BfParser_Reduce(void* bfParser, void* bfPassInstance); [CallingConvention(.Stdcall), CLink] - static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping); + static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol); [CallingConvention(.Stdcall), CLink] static extern char8* BfParser_GetDebugExpressionAt(void* bfParser, int32 cursorIdx); @@ -209,8 +210,9 @@ namespace IDE.Compiler public void Reformat(int formatStart, int formatEnd, out int32[] char8Mapping, String str) { int32* char8MappingPtr; - var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr); - str.Append(stringPtr); + var maxCol = gApp.mSettings.mEditorSettings.mWrapCommentsAt; + var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr, maxCol); + str.Append(stringPtr); char8Mapping = new int32[str.Length]; for (int32 i = 0; i < char8Mapping.Count; i++) diff --git a/IDE/src/Compiler/BfSystem.bf b/IDE/src/Compiler/BfSystem.bf index 0d7b93ee..cd1b057e 100644 --- a/IDE/src/Compiler/BfSystem.bf +++ b/IDE/src/Compiler/BfSystem.bf @@ -51,7 +51,7 @@ namespace IDE.Compiler static extern char8* BfSystem_GetNamespaceSearch(void* bfSystem, char8* typeName, void* project); [CallingConvention(.Stdcall), CLink] - static extern void* BfSystem_CreateProject(void* bfSystem, char8* projectName); + static extern void* BfSystem_CreateProject(void* bfSystem, char8* projectName, char8* projectDir); [CallingConvention(.Stdcall), CLink] static extern void BfSystem_ClearTypeOptions(void* bfSystem); @@ -142,7 +142,7 @@ namespace IDE.Compiler { using (mMonitor.Enter()) { - var bfProject = CreateProject(project.mProjectName); + var bfProject = CreateProject(project.mProjectName, project.mProjectDir); mProjectMap[project] = bfProject; } } @@ -188,10 +188,10 @@ namespace IDE.Compiler outNamespaceSearch.Append(namespaceSearch); } - public BfProject CreateProject(String projectName) + public BfProject CreateProject(String projectName, String projectDir) { BfProject project = new BfProject(); - project.mNativeBfProject = BfSystem_CreateProject(mNativeBfSystem, projectName); + project.mNativeBfProject = BfSystem_CreateProject(mNativeBfSystem, projectName, projectDir); return project; } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 0131b705..3cdca790 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -169,6 +169,8 @@ namespace IDE public bool mLastCompileHadMessages; public bool mPauseOnExit; public bool mDbgDelayedAutocomplete; + public bool mDbgTimeAutocomplete; + public bool mDbgPerfAutocomplete; public BeefConfig mBeefConfig = new BeefConfig() ~ delete _; public List mDeferredFails = new .() ~ DeleteContainerAndItems!(_); public String mInitialCWD = new .() ~ delete _; @@ -2314,6 +2316,11 @@ namespace IDE widget.RemoveSelf(); } + WithSourceViewPanels(scope (sourceViewPanel) => + { + sourceViewPanel.Dispose(); + }); + if (!mRunningTestScript) { mActiveDocumentsTabbedView = null; @@ -2425,11 +2432,27 @@ namespace IDE } [IDECommand] - void CommentSelection() + void CommentBlock() { var sewc = GetActiveSourceEditWidgetContent(); if (sewc != null) - sewc.ToggleComment(true); + sewc.CommentBlock(); + } + + [IDECommand] + void CommentLines() + { + var sewc = GetActiveSourceEditWidgetContent(); + if (sewc != null) + sewc.CommentLines(); + } + + [IDECommand] + void CommentToggle() + { + var sewc = GetActiveSourceEditWidgetContent(); + if (sewc != null) + sewc.ToggleComment(); } [IDECommand] @@ -3936,7 +3959,7 @@ namespace IDE if (sourceViewPanel != null) { if (sourceViewPanel.mEditWidget.mEditWidgetContent.GetCursorLineChar(var line, var lineChar)) - sourceViewPanel.UpdateMouseover(true, true, line, lineChar); + sourceViewPanel.UpdateMouseover(true, true, line, lineChar, true); } } @@ -4874,6 +4897,14 @@ namespace IDE CreateDefaultLayout(false); } + [IDECommand] + public void SafeModeToggle() + { + mSafeMode = !mSafeMode; + mNoResolve = mSafeMode; + mWantsBeefClean = true; + } + [IDECommand] public void ShowKeyboardShortcuts() { @@ -5240,6 +5271,11 @@ namespace IDE menu.SetDisabled(!mDebugger.mIsRunning); } + public void UpdateMenuItem_DebugOrTestRunning(IMenu menu) + { + menu.SetDisabled(!mDebugger.mIsRunning && (mTestManager == null)); + } + public void UpdateMenuItem_DebugStopped_HasWorkspace(IMenu menu) { menu.SetDisabled(mDebugger.mIsRunning || !mWorkspace.IsInitialized); @@ -5310,6 +5346,7 @@ namespace IDE AddMenuItem(prefMenu, "&Settings", "Settings"); AddMenuItem(prefMenu, "Reload Settings", "Reload Settings"); AddMenuItem(prefMenu, "Reset UI", "Reset UI"); + AddMenuItem(prefMenu, "Safe Mode", "Safe Mode Toggle", new (menu) => { menu.SetCheckState(mSafeMode ? 1 : 0); }, null, true, mSafeMode ? 1 : 0); AddMenuItem(subMenu, "Close Workspace", "Close Workspace", new => UpdateMenuItem_HasWorkspace); AddMenuItem(subMenu, "E&xit", "Exit"); @@ -5386,7 +5423,9 @@ namespace IDE advancedEditMenu.AddMenuItem(null); AddMenuItem(advancedEditMenu, "Make Uppercase", "Make Uppercase"); AddMenuItem(advancedEditMenu, "Make Lowercase", "Make Lowercase"); - AddMenuItem(advancedEditMenu, "Comment Selection", "Comment Selection"); + AddMenuItem(advancedEditMenu, "Comment Block", "Comment Block"); + AddMenuItem(advancedEditMenu, "Comment Lines", "Comment Lines"); + AddMenuItem(advancedEditMenu, "Comment Toggle", "Comment Toggle"); AddMenuItem(advancedEditMenu, "Uncomment Selection", "Uncomment Selection"); AddMenuItem(advancedEditMenu, "Reformat Document", "Reformat Document"); mViewWhiteSpace.mMenu = AddMenuItem(advancedEditMenu, "View White Space", "View White Space", null, null, true, mViewWhiteSpace.Bool ? 1 : 0); @@ -5397,6 +5436,8 @@ namespace IDE var internalEditMenu = subMenu.AddMenuItem("Internal"); internalEditMenu.AddMenuItem("Hilight Cursor References", null, new (menu) => { ToggleCheck(menu, ref gApp.mSettings.mEditorSettings.mHiliteCursorReferences); }, null, null, true, gApp.mSettings.mEditorSettings.mHiliteCursorReferences ? 1 : 0); internalEditMenu.AddMenuItem("Delayed Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgDelayedAutocomplete); }, null, null, true, gApp.mDbgDelayedAutocomplete ? 1 : 0); + internalEditMenu.AddMenuItem("Time Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgTimeAutocomplete); }, null, null, true, gApp.mDbgTimeAutocomplete ? 1 : 0); + internalEditMenu.AddMenuItem("Perf Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgPerfAutocomplete); }, null, null, true, gApp.mDbgPerfAutocomplete ? 1 : 0); } ////////// @@ -5456,7 +5497,7 @@ namespace IDE AddMenuItem(subMenu, "Start With&out Compiling", "Start Without Compiling", new => UpdateMenuItem_DebugStopped_HasWorkspace); AddMenuItem(subMenu, "&Launch Process...", "Launch Process", new => UpdateMenuItem_DebugStopped); AddMenuItem(subMenu, "&Attach to Process...", "Attach to Process", new => UpdateMenuItem_DebugStopped); - AddMenuItem(subMenu, "&Stop Debugging", "Stop Debugging", new => UpdateMenuItem_DebugRunning); + AddMenuItem(subMenu, "&Stop Debugging", "Stop Debugging", new => UpdateMenuItem_DebugOrTestRunning); AddMenuItem(subMenu, "Break All", "Break All", new => UpdateMenuItem_DebugNotPaused); AddMenuItem(subMenu, "Remove All Breakpoints", "Remove All Breakpoints"); AddMenuItem(subMenu, "Show &Disassembly", "Show Disassembly"); @@ -5712,14 +5753,20 @@ namespace IDE { let sewc = editWidget.mEditWidgetContent as SourceEditWidgetContent; if (sewc != null) - return sewc; + { + if (sewc.mEditWidget.mHasFocus) + return sewc; + return null; + } } } var activeTextPanel = GetActivePanel() as TextPanel; if (activeTextPanel != null) { - return activeTextPanel.EditWidget.mEditWidgetContent as SourceEditWidgetContent; + let sewc = activeTextPanel.EditWidget.mEditWidgetContent as SourceEditWidgetContent; + if ((sewc != null) && (sewc.mEditWidget.mHasFocus)) + return sewc; } return null; @@ -9167,6 +9214,9 @@ namespace IDE bool doCompile = false; if (lastCompileHadMessages) doCompile = true; + + bool needsComptime = bfCompiler.GetLastHadComptimeRebuilds(); + if ((!workspaceOptions.mIncrementalBuild) && (!lastCompileHadMessages)) { tryQueueFiles = false; @@ -9177,6 +9227,9 @@ namespace IDE } } + if (needsComptime) + tryQueueFiles = true; + if (hotProject != null) { mWorkspace.mHadHotCompileSinceLastFullCompile = true; @@ -9210,6 +9263,9 @@ namespace IDE } } + if (needsComptime) + doCompile = true; + if (!success) { bfCompiler.QueueDeletePassInstance(passInstance); @@ -10748,7 +10804,7 @@ namespace IDE Beef requires the Microsoft C++ build tools for Visual Studio 2013 or later, but they don't seem to be installed. Install just Microsoft Visual C++ Build Tools or the entire Visual Studio suite from: - https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019 + https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022 """; #if CLI @@ -10759,7 +10815,7 @@ namespace IDE dlg.AddOkCancelButtons(new (dlg) => { ProcessStartInfo psi = scope ProcessStartInfo(); - psi.SetFileName("https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019"); + psi.SetFileName("https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022"); psi.UseShellExecute = true; psi.SetVerb("Open"); var process = scope SpawnedProcess(); @@ -12040,11 +12096,11 @@ namespace IDE if (mErrorsPanel != null) mErrorsPanel.ClearParserErrors(null); - delete mBfResolveCompiler; - delete mBfResolveSystem; - delete mBfResolveHelper; - delete mBfBuildCompiler; - delete mBfBuildSystem; + DeleteAndNullify!(mBfResolveCompiler); + DeleteAndNullify!(mBfResolveSystem); + DeleteAndNullify!(mBfResolveHelper); + DeleteAndNullify!(mBfBuildCompiler); + DeleteAndNullify!(mBfBuildSystem); /// mDebugger.FullReportMemory(); @@ -13698,7 +13754,6 @@ namespace IDE [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] public static extern bool MessageBeep(MessageBeepType type); #endif - } static diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index 1c3a1bec..dab259bd 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -626,6 +626,7 @@ namespace IDE public FileRecoveryKind mEnableFileRecovery = .Yes; public bool mFormatOnSave = false; public bool mSyncWithWorkspacePanel = false; + public int32 mWrapCommentsAt = 0; public void Serialize(StructuredData sd) { @@ -652,6 +653,7 @@ namespace IDE sd.Add("EnableFileRecovery", mEnableFileRecovery); sd.Add("FormatOnSave", mFormatOnSave); sd.Add("SyncWithWorkspacePanel", mSyncWithWorkspacePanel); + sd.Add("WrapCommentsAt", mWrapCommentsAt); } public void Deserialize(StructuredData sd) @@ -682,6 +684,7 @@ namespace IDE sd.GetEnum("EnableFileRecovery", ref mEnableFileRecovery); sd.Get("FormatOnSave", ref mFormatOnSave); sd.Get("SyncWithWorkspacePanel", ref mSyncWithWorkspacePanel); + sd.Get("WrapCommentsAt", ref mWrapCommentsAt); } public void SetDefaults() @@ -756,7 +759,9 @@ namespace IDE Add("Cancel Build", "Ctrl+Break"); Add("Close Document", "Ctrl+W"); Add("Compile File", "Ctrl+F7"); - Add("Comment Selection", "Ctrl+K, Ctrl+C"); + Add("Comment Block", "Ctrl+K, Ctrl+C"); + Add("Comment Lines", "Ctrl+K, Ctrl+/"); + Add("Comment Toggle", "Ctrl+K, Ctrl+T"); Add("Duplicate Line", "Ctrl+D"); Add("Find Class", "Alt+Shift+L"); Add("Find in Document", "Ctrl+F"); @@ -892,7 +897,10 @@ namespace IDE { curCmdMap = (*valuePtr) as CommandMap; if (curCmdMap == null) + { + curCmdMap.FailValues.Add(ideCommand); break; + } } else { @@ -905,7 +913,10 @@ namespace IDE if (checkPrevCmd.mContextFlags == ideCommand.mContextFlags) gApp.OutputLineSmart("ERROR: The same key is bound for '{0}' and '{1}'", checkPrevCmd.mName, entry.mCommand); if (checkPrevCmd.mNext == null) + { + curCmdMap.FailValues.Add(ideCommand); break; + } checkPrevCmd = checkPrevCmd.mNext; } checkPrevCmd.mNext = ideCommand; diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index b9b923fa..eeb42bfb 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -1165,6 +1165,7 @@ namespace IDE.ui } } + public Stopwatch mStopwatch ~ delete _; public EditWidget mTargetEditWidget; public Event mOnAutoCompleteInserted ~ _.Dispose(); public Event mOnClosed ~ _.Dispose(); diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index f64e2724..be5f5fbb 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -136,17 +136,15 @@ namespace IDE.ui ClearAndDeleteItems(mResolveErrors); mResolveErrors.Capacity = mResolveErrors.Count; } - + var bfl = scope:: List(); for (int32 errorIdx = 0; errorIdx < errorCount; errorIdx++) { BfPassInstance.BfError bfError = new BfPassInstance.BfError(); passInstance.GetErrorData(errorIdx, bfError, true); + if (bfError.mFilePath == null) + bfError.mFilePath = new String(""); //for sort below - if (bfError.mIsWarning) - mWarningCount++; - else - mErrorCount++; - + bfl.Add(bfError); for (int32 moreInfoIdx < bfError.mMoreInfoCount) { BfPassInstance.BfError moreInfo = new BfPassInstance.BfError(); @@ -155,12 +153,26 @@ namespace IDE.ui bfError.mMoreInfo = new List(); bfError.mMoreInfo.Add(moreInfo); } + } + + function int(int lhs, int rhs) ascLambda = (lhs, rhs) => lhs <=> rhs; + bfl.Sort(scope (lhs, rhs) => ascLambda(lhs.mFilePath.GetHashCode()+lhs.mSrcStart, rhs.mFilePath.GetHashCode()+rhs.mSrcStart)); + + for (int32 errorIdx = 0; errorIdx < bfl.Count; errorIdx++) + { + var bfError = bfl[errorIdx]; + + if (bfError.mIsWarning) + { + mWarningCount++; + } + else + mErrorCount++; if (passKind == .Parse) { if (bfError.mFilePath == null) bfError.mFilePath = new String(""); - bool added = mParseErrors.TryAdd(bfError.mFilePath, var keyPtr, var valuePtr); if (added) { @@ -170,7 +182,7 @@ namespace IDE.ui (*valuePtr).Add(bfError); } else - mResolveErrors.Add(bfError); + mResolveErrors.Add(bfError); mDataId++; } @@ -354,7 +366,7 @@ namespace IDE.ui public override void Update() { base.Update(); - + if (!mVisible) { // Very dirty @@ -369,7 +381,8 @@ namespace IDE.ui else mDirtyTicks++; - ProcessErrors(); + if(mDirtyTicks==0) + ProcessErrors(); } public void SetNeedsResolveAll() @@ -379,7 +392,8 @@ namespace IDE.ui public void ShowErrorNext() { - ProcessErrors(); + if(mDirtyTicks==0) + ProcessErrors(); bool foundFocused = false; let root = mErrorLV.GetRoot(); diff --git a/IDE/src/ui/OutputPanel.bf b/IDE/src/ui/OutputPanel.bf index e99e10a6..a60696f8 100644 --- a/IDE/src/ui/OutputPanel.bf +++ b/IDE/src/ui/OutputPanel.bf @@ -139,7 +139,8 @@ namespace IDE.ui mOutputWidget.SetText(""); for (var widgetEntry in mInlineWidgets) { - widgetEntry.mWidget.RemoveSelf(); + if (widgetEntry.mWidget.mParent != null) + widgetEntry.mWidget.RemoveSelf(); delete widgetEntry.mWidget; } mInlineWidgets.Clear(); diff --git a/IDE/src/ui/ProfilePanel.bf b/IDE/src/ui/ProfilePanel.bf index 2ca2beb8..033c553e 100644 --- a/IDE/src/ui/ProfilePanel.bf +++ b/IDE/src/ui/ProfilePanel.bf @@ -293,6 +293,10 @@ namespace IDE.ui } } + struct ThreadEntry : this(int32 mThreadId, int32 mCPUUsage, StringView mName) + { + } + void PopulateThreadList(Menu menu) { if (mProfiler == null) @@ -307,6 +311,7 @@ namespace IDE.ui var threadListStr = scope String(); mProfiler.GetThreadList(threadListStr); + List entries = scope .(); for (var entry in threadListStr.Split('\n')) { if (entry.Length == 0) @@ -314,20 +319,35 @@ namespace IDE.ui var dataItr = entry.Split('\t'); - int32 threadId = int32.Parse(dataItr.GetNext()); - StringView threadName = dataItr.GetNext(); + ThreadEntry threadEntry = default; + threadEntry.mThreadId = int32.Parse(dataItr.GetNext()); + threadEntry.mCPUUsage = int32.Parse(dataItr.GetNext()); + threadEntry.mName = dataItr.GetNext(); + entries.Add(threadEntry); + } + entries.Sort(scope (lhs, rhs) => + { + int cmp = rhs.mCPUUsage <=> lhs.mCPUUsage; + if (cmp == 0) + cmp = lhs.mThreadId <=> rhs.mThreadId; + return cmp; + }); + + for (var entry in entries) + { String threadStr = null; var str = scope String(); - str.AppendF("{0}", threadId); - if (!threadName.IsEmpty) + str.AppendF("{0}", entry.mThreadId); + str.AppendF($" ({entry.mCPUUsage}%)"); + if (!entry.mName.IsEmpty) { - threadStr = new String(threadName); - str.AppendF(" - {0}", threadName); + threadStr = new String(entry.mName); + str.AppendF($" - {entry.mName}"); } subItem = menu.AddItem(str); - subItem.mOnMenuItemSelected.Add(new (item) => { Show(threadId, threadStr); } ~ delete threadStr); + subItem.mOnMenuItemSelected.Add(new (item) => { Show(entry.mThreadId, threadStr); } ~ delete threadStr); } } diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index a3824a65..b82bd49a 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -127,7 +127,8 @@ namespace IDE.ui AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery"); AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); - + AddPropertiesItem(category, "Wrap Comments at Column", "mWrapCommentsAt"); + category.Open(true, true); } diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index dbb19ef7..f9363bf5 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2160,11 +2160,18 @@ namespace IDE.ui return true; } - public bool ToggleComment(bool? doComment = null) + public bool CommentBlock() { + bool? doComment = true; + if (CheckReadOnly()) return false; + var startLineAndCol = CursorLineAndColumn; + int startTextPos = CursorTextPos; + var prevSelection = mSelection; + bool hadSelection = HasSelection(); + if ((!HasSelection()) && (doComment != null)) { CursorToLineEnd(); @@ -2173,14 +2180,15 @@ namespace IDE.ui mSelection = .(CursorTextPos, cursorEndPos); } - if ((HasSelection()) && (mSelection.Value.Length > 1)) - { - var startLineAndCol = CursorLineAndColumn; - - UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); + if ((HasSelection()) && (mSelection.Value.Length > 1)) + { + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentBlock"); mData.mUndoManager.Add(undoBatchStart); - mData.mUndoManager.Add(new SetCursorAction(this)); + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); int minPos = mSelection.GetValueOrDefault().MinPos; int maxPos = mSelection.GetValueOrDefault().MaxPos; @@ -2200,20 +2208,7 @@ namespace IDE.ui int firstCharPos = minPos + (startLen - afterTrimStart); int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); - if ((doComment != true) && (trimmedStr.StartsWith("/*"))) - { - if (trimmedStr.EndsWith("*/")) - { - mSelection = EditSelection(firstCharPos, firstCharPos + 2); - DeleteChar(); - mSelection = EditSelection(lastCharPos - 4, lastCharPos - 2); - DeleteChar(); - - if (doComment != null) - mSelection = EditSelection(firstCharPos, lastCharPos - 4); - } - } - else if (doComment != false) + if (doComment != false) { CursorTextPos = firstCharPos; InsertAtCursor("/*"); @@ -2227,13 +2222,320 @@ namespace IDE.ui if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); - CursorLineAndColumn = startLineAndCol; + if (startTextPos <= minPos) + CursorLineAndColumn = startLineAndCol; + else if (startTextPos < maxPos) + CursorTextPos = startTextPos + 2; - if (doComment == null) + if ((doComment == null) || (!hadSelection)) mSelection = null; - return true; - } + return true; + } + + return false; + } + + public bool CommentLines() + { + if (CheckReadOnly()) + return false; + + int startTextPos = CursorTextPos; + var prevSelection = mSelection; + bool hadSelection = HasSelection(); + var startLineAndCol = CursorLineAndColumn; + if (!HasSelection()) + { + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + CursorToLineStart(false); + mSelection = .(CursorTextPos, cursorEndPos); + } + + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentLines"); + mData.mUndoManager.Add(undoBatchStart); + + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); + + int minPos = mSelection.GetValueOrDefault().MinPos; + int maxPos = mSelection.GetValueOrDefault().MaxPos; + mSelection = null; + + while (minPos > 0) + { + var c = mData.mText[minPos - 1].mChar; + if (c == '\n') + break; + minPos--; + } + + bool hadMaxChar = false; + int checkMaxPos = maxPos; + while (checkMaxPos > 0) + { + var c = mData.mText[checkMaxPos - 1].mChar; + if (c == '\n') + break; + if ((c != '\t') && (c != ' ')) + { + hadMaxChar = true; + break; + } + checkMaxPos--; + } + + if (!hadMaxChar) + { + checkMaxPos = maxPos; + while (checkMaxPos < mData.mTextLength) + { + var c = mData.mText[checkMaxPos].mChar; + if (c == '\n') + break; + if ((c != '\t') && (c != ' ')) + { + maxPos = checkMaxPos + 1; + break; + } + checkMaxPos++; + } + } + + int wantLineCol = -1; + int lineStartCol = 0; + bool didLineComment = false; + + for (int i = minPos; i < maxPos; i++) + { + var c = mData.mText[i].mChar; + if (didLineComment) + { + if (c == '\n') + { + didLineComment = false; + lineStartCol = 0; + } + continue; + } + if (c == '\t') + lineStartCol += 4; + else if (c == ' ') + lineStartCol++; + else + { + if (wantLineCol == -1) + wantLineCol = lineStartCol; + else + wantLineCol = Math.Min(wantLineCol, lineStartCol); + didLineComment = true; + } + } + wantLineCol = Math.Max(0, wantLineCol); + + didLineComment = false; + lineStartCol = 0; + for (int i = minPos; i < maxPos; i++) + { + var c = mData.mText[i].mChar; + if (didLineComment) + { + if (c == '\n') + { + didLineComment = false; + lineStartCol = 0; + } + continue; + } + + bool commentNow = false; + if ((wantLineCol != -1) && (lineStartCol >= wantLineCol)) + commentNow = true; + + if (c == '\t') + lineStartCol += 4; + else if (c == ' ') + lineStartCol++; + else + commentNow = true; + + if (commentNow) + { + CursorTextPos = i; + String str = scope .(); + while (lineStartCol + 4 <= wantLineCol) + { + lineStartCol += 4; + str.Append("\t"); + } + str.Append("//"); + InsertAtCursor(str); + didLineComment = true; + maxPos += str.Length; + } + } + mSelection = EditSelection(minPos, maxPos); + + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol; + + if (!hadSelection) + mSelection = null; + + return true; + } + + void FixSelection() + { + if (!HasSelection()) + return; + if (CursorTextPos >= mSelection.Value.MaxPos) + CursorTextPos = mSelection.Value.MaxPos; + if (mSelection.Value.MaxPos - mSelection.Value.MinPos <= 1) + { + mSelection = null; + return; + } + } + + public bool ToggleComment(bool? doComment = null) + { + if (CheckReadOnly()) + return false; + + int startTextPos = CursorTextPos; + bool doLineComment = false; + var prevSelection = mSelection; + + LineAndColumn? startLineAndCol = CursorLineAndColumn; + if (!HasSelection()) + { + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + CursorToLineStart(false); + mSelection = .(CursorTextPos, cursorEndPos); + doLineComment = true; + } + + if ((HasSelection()) && (mSelection.Value.Length > 0)) + { + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); + mData.mUndoManager.Add(undoBatchStart); + + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); + + int minPos = mSelection.GetValueOrDefault().MinPos; + int maxPos = mSelection.GetValueOrDefault().MaxPos; + mSelection = null; + + var str = scope String(); + ExtractString(minPos, maxPos - minPos, str); + var trimmedStr = scope String(); + trimmedStr.Append(str); + int32 startLen = (int32)trimmedStr.Length; + trimmedStr.TrimStart(); + int32 afterTrimStart = (int32)trimmedStr.Length; + trimmedStr.TrimEnd(); + int32 afterTrimEnd = (int32)trimmedStr.Length; + trimmedStr.Append('\n'); + + int firstCharPos = minPos + (startLen - afterTrimStart); + int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); + + if (afterTrimEnd == 0) + { + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol.Value; + + if (doComment == null) + mSelection = null; + + return false; // not sure if this should be false in blank/only whitespace selection case + } + else if ((doComment != true) && (trimmedStr.StartsWith("//"))) + { + for (int i = firstCharPos; i <= lastCharPos; i++) + { + if ((minPos == 0 && i == 0) || (minPos>=0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) + if (SafeGetChar(i - 0) == '/' && SafeGetChar(i + 1) == '/') + { + mSelection = EditSelection(i - 0, i + 2); + DeleteSelection(); + lastCharPos -= 2; + while (i < maxPos && SafeGetChar(i) != '\n') + { + i++; + } + } + } + + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + mSelection = .(minPos, cursorEndPos); + } + else if ((doComment != true) && (trimmedStr.StartsWith("/*"))) + { + if (trimmedStr.EndsWith("*/\n")) + { + mSelection = EditSelection(firstCharPos, firstCharPos + 2); + DeleteChar(); + mSelection = EditSelection(lastCharPos - 4, lastCharPos - 2); + DeleteChar(); + + if (prevSelection != null) + mSelection = EditSelection(firstCharPos, lastCharPos - 4); + } + } + else if (doComment != false) + { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab + if (doLineComment) + { + CursorTextPos = minPos; + InsertAtCursor("//"); //goes here if no selection + } + else + { + CursorTextPos = firstCharPos; + InsertAtCursor("/*"); + CursorTextPos = lastCharPos + 2; + InsertAtCursor("*/"); + } + + mSelection = EditSelection(firstCharPos, lastCharPos + 4); + if (startTextPos <= minPos) + CursorLineAndColumn = startLineAndCol.Value; + else + CursorTextPos = startTextPos + 2; + startLineAndCol = null; + } + else + { + mSelection = prevSelection; + } + + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + if (startLineAndCol != null) + CursorLineAndColumn = startLineAndCol.Value; + + if (prevSelection == null) + mSelection = null; + + FixSelection(); + + return true; + } return false; } @@ -2275,6 +2577,9 @@ namespace IDE.ui public void DuplicateLine() { + if ((CheckReadOnly()) || (!mAllowVirtualCursor)) + return; + UndoBatchStart undoBatchStart = new UndoBatchStart("duplicateLine"); mData.mUndoManager.Add(undoBatchStart); @@ -3103,7 +3408,7 @@ namespace IDE.ui return; } - if ((keyChar == '/') && (ToggleComment())) + if ((keyChar == '/') && (HasSelection()) && (ToggleComment())) { return; } diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index eb6f3f43..7d09f003 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -160,6 +160,8 @@ namespace IDE.ui { public int32 mCursorPos; public String mResult ~ delete _; + public int32? mLine; + public int32? mLineChar; public ~this() { @@ -621,6 +623,10 @@ namespace IDE.ui //Classify(options.HasFlag(.HighPriority) ? ResolveType.Autocomplete_HighPri : ResolveType.Autocomplete); ResolveParams resolveParams = new ResolveParams(); + if (gApp.mDbgTimeAutocomplete) + resolveParams.mStopwatch = new .()..Start(); + if (gApp.mDbgPerfAutocomplete) + resolveParams.mProfileInstance = Profiler.StartSampling("Autocomplete").GetValueOrDefault(); resolveParams.mIsUserRequested = options.HasFlag(.UserRequested); resolveParams.mDoFuzzyAutoComplete = gApp.mSettings.mEditorSettings.mFuzzyAutoComplete; Classify(.Autocomplete, resolveParams); @@ -1186,7 +1192,7 @@ namespace IDE.ui //if (mCurParser != null) { if (gApp.mWorkspace.mProjectLoadState != .Loaded) - return false; + return true; if (!isHi) Debug.Assert(!mIsPerformingBackgroundClassify); @@ -2336,6 +2342,11 @@ namespace IDE.ui if (mDisposed) return; + if (mProjectSource?.mEditData?.HasTextChanged() == true) + { + mProjectSource.ClearEditData(); + } + ProcessDeferredResolveResults(-1); if (IDEApp.sApp.mLastActiveSourceViewPanel == this) @@ -4725,7 +4736,7 @@ namespace IDE.ui delete parser; } - public void UpdateMouseover(bool mouseoverFired, bool mouseInbounds, int line, int lineChar) + public void UpdateMouseover(bool mouseoverFired, bool mouseInbounds, int line, int lineChar, bool isManual = false) { @@ -5011,6 +5022,11 @@ namespace IDE.ui mHoverResolveTask = new HoverResolveTask(); mHoverResolveTask.mCursorPos = (int32)textIdx; + if (isManual) + { + mHoverResolveTask.mLine = (.)line; + mHoverResolveTask.mLineChar = (.)lineChar; + } } } @@ -5204,6 +5220,16 @@ namespace IDE.ui #if IDE_C_SUPPORT hasClangHoverErrorData = mClangHoverErrorData != null; #endif + + if (mHoverResolveTask != null) + { + if (mHoverResolveTask.mLine != null) + { + UpdateMouseover(true, true, mHoverResolveTask.mLine.Value, mHoverResolveTask.mLineChar.Value, true); + return; + } + } + if (((mouseoverFired) || (mHoverWatch != null) || (hasClangHoverErrorData) || (mHoverResolveTask?.mResult != null)) && (mousePos.x >= 0)) { @@ -5526,6 +5552,13 @@ namespace IDE.ui HandleResolveResult(resolveResult.mResolveType, resolveResult.mAutocompleteInfo, resolveResult); + if (resolveResult.mStopwatch != null) + { + resolveResult.mStopwatch.Stop(); + if (var autoComplete = GetAutoComplete()) + Debug.WriteLine($"Autocomplete {resolveResult.mStopwatch.ElapsedMilliseconds}ms entries: {autoComplete.mAutoCompleteListWidget.mEntryList.Count}"); + } + //Debug.WriteLine("ProcessDeferredResolveResults finished {0}", resolveResult.mResolveType); //bool checkIt = (mFilePath.Contains("Program.bf")) && (mEditWidget.mEditWidgetContent.mData.mCurTextVersionId > 3); diff --git a/IDE/src/ui/WatchPanel.bf b/IDE/src/ui/WatchPanel.bf index 06da55be..8779e76d 100644 --- a/IDE/src/ui/WatchPanel.bf +++ b/IDE/src/ui/WatchPanel.bf @@ -2765,7 +2765,10 @@ namespace IDE.ui { String evalStr = scope String(); CompactChildExpression(listViewItem, evalStr); - evalStr.Insert(0, "&"); + if (evalStr.StartsWith("*")) + evalStr.Remove(0, 1); + else + evalStr.Insert(0, "&"); gApp.mBreakpointPanel.CreateMemoryBreakpoint(evalStr); gApp.MarkDirty(); }); diff --git a/IDEHelper/Backend/BeMCContext.cpp b/IDEHelper/Backend/BeMCContext.cpp index 1112dca9..77dbb095 100644 --- a/IDEHelper/Backend/BeMCContext.cpp +++ b/IDEHelper/Backend/BeMCContext.cpp @@ -2171,6 +2171,8 @@ BeMCOperand BeMCContext::GetOperand(BeValue* value, bool allowMetaResult, bool a auto vregInfo = GetVRegInfo(tlsVReg); vregInfo->mMustExist = true; vregInfo->mForceReg = true; + vregInfo->mDisableR12 = true; + vregInfo->mDisableR13 = true; mTLSVRegIdx = tlsVReg.mVRegIdx; } @@ -15930,7 +15932,7 @@ void BeMCContext::Generate(BeFunction* function) mDbgPreferredRegs[32] = X64Reg_R8;*/ //mDbgPreferredRegs[8] = X64Reg_RAX; - //mDebugging = (function->mName == "?Load@TestProgram@BeefTest@bf@@SA?AUHandle@23@XZ"); + //mDebugging = (function->mName == "?InitThread@Foo@BeefTest@bf@@CA?AU?$Result@X@System@3@H@Z"); // || (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ"); // || (function->mName == "?Hey@Blurg@bf@@SAXXZ") // ; diff --git a/IDEHelper/CMakeLists.txt b/IDEHelper/CMakeLists.txt index 46a478e9..a107fb24 100644 --- a/IDEHelper/CMakeLists.txt +++ b/IDEHelper/CMakeLists.txt @@ -122,7 +122,7 @@ if(MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W3 /GL /Od /Oi /Gy /EHsc") endif(MSVC) if(NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -Wno-multichar -Wno-invalid-offsetof") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fno-rtti -Wno-multichar -Wno-invalid-offsetof") endif(NOT MSVC) ################ Files ################ diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index ba777852..b1950a53 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -360,6 +360,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) //mMaxInterfaceSlots = 16; mMaxInterfaceSlots = -1; mInterfaceSlotCountChanged = false; + mLastHadComptimeRebuilds = false; + mHasComptimeRebuilds = false; mHSPreserveIdx = 0; mCompileLogFP = NULL; @@ -825,7 +827,7 @@ void BfCompiler::GetTestMethods(BfVDataModule* bfModule, Array& test auto _CheckMethod = [&](BfTypeInstance* typeInstance, BfMethodInstance* methodInstance) { - auto project = typeInstance->mTypeDef->mProject; + auto project = methodInstance->mMethodDef->mDeclaringType->mProject; if (project->mTargetType != BfTargetType_BeefTest) return; if (project != bfModule->mProject) @@ -913,7 +915,8 @@ void BfCompiler::EmitTestMethod(BfVDataModule* bfModule, Array& test auto methodInstance = testMethod.mMethodInstance; auto typeInstance = methodInstance->GetOwner(); testMethod.mName += bfModule->TypeToString(typeInstance); - testMethod.mName += "."; + if (!testMethod.mName.IsEmpty()) + testMethod.mName += "."; testMethod.mName += methodInstance->mMethodDef->mName; testMethod.mName += "\t"; @@ -1021,8 +1024,11 @@ void BfCompiler::EmitTestMethod(BfVDataModule* bfModule, Array& test else { for (int defaultIdx = 0; defaultIdx < (int)methodInstance->mDefaultValues.size(); defaultIdx++) - { - auto castedVal = bfModule->Cast(methodInstance->mMethodDef->GetRefNode(), methodInstance->mDefaultValues[defaultIdx], methodInstance->GetParamType(defaultIdx)); + { + auto constHolder = methodInstance->GetOwner()->mConstHolder; + auto defaultTypedValue = methodInstance->mDefaultValues[defaultIdx]; + auto defaultVal = bfModule->ConstantToCurrent(constHolder->GetConstant(defaultTypedValue.mValue), constHolder, defaultTypedValue.mType); + auto castedVal = bfModule->Cast(methodInstance->mMethodDef->GetRefNode(), BfTypedValue(defaultVal, defaultTypedValue.mType), methodInstance->GetParamType(defaultIdx)); if (castedVal) { BfExprEvaluator exprEvaluator(bfModule); @@ -2927,7 +2933,7 @@ void BfCompiler::GenerateDynCastData() void BfCompiler::UpdateRevisedTypes() { - BfLogSysM("UpdateRevisedTypes\n"); + BfLogSysM("BfCompiler::UpdateRevisedTypes\n"); BP_ZONE("BfCompiler::UpdateRevisedTypes"); // See if we have any name conflicts and remove those @@ -6561,6 +6567,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) // Inc revision for next run through Compile mRevision++; + mHasComptimeRebuilds = false; int revision = mRevision; BfLogSysM("Compile Start. Revision: %d. HasParser:%d AutoComplete:%d\n", revision, (mResolvePassData != NULL) && (mResolvePassData->mParser != NULL), @@ -7021,27 +7028,34 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) if (hasTests) { + HashSet projectSet; + for (auto type : mContext->mResolvedTypes) { auto typeInstance = type->ToTypeInstance(); - if ((typeInstance != NULL) && - (typeInstance->mTypeDef->mProject->mTargetType == BfTargetType_BeefTest)) - { - bool typeHasTest = false; + if (typeInstance != NULL) + { for (auto& methodInstanceGroup : typeInstance->mMethodInstanceGroups) { if (methodInstanceGroup.mDefault != NULL) { auto methodInstance = methodInstanceGroup.mDefault; + auto project = methodInstance->mMethodDef->mDeclaringType->mProject; + if (project->mTargetType != BfTargetType_BeefTest) + continue; if ((methodInstance->GetCustomAttributes() != NULL) && (methodInstance->GetCustomAttributes()->Contains(mTestAttributeTypeDef))) { - typeHasTest = true; + projectSet.Add(project); } } } - if (typeHasTest) - mContext->MarkUsedModules(typeInstance->mTypeDef->mProject, typeInstance->mModule); + if (!projectSet.IsEmpty()) + { + for (auto project : projectSet) + mContext->MarkUsedModules(project, typeInstance->mModule); + projectSet.Clear(); + } } } } @@ -7494,6 +7508,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) return false; } + if (didCancel) + mLastHadComptimeRebuilds = mHasComptimeRebuilds || mLastHadComptimeRebuilds; + else + mLastHadComptimeRebuilds = mHasComptimeRebuilds; + return !didCancel && !mHasQueuedTypeRebuilds; } @@ -9104,6 +9123,11 @@ BF_EXPORT int BF_CALLTYPE BfCompiler_GetCurConstEvalExecuteId(BfCompiler* bfComp return bfCompiler->mCEMachine->mExecuteId; } +BF_EXPORT float BF_CALLTYPE BfCompiler_GetLastHadComptimeRebuilds(BfCompiler* bfCompiler) +{ + return bfCompiler->mLastHadComptimeRebuilds; +} + BF_EXPORT void BF_CALLTYPE BfCompiler_Cancel(BfCompiler* bfCompiler) { bfCompiler->Cancel(); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 9c2dbef6..4c79b85c 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -328,7 +328,9 @@ public: bool mFastFinish; bool mHasQueuedTypeRebuilds; // Infers we had a fast finish that requires a type rebuild bool mHadCancel; - bool mWantsDeferMethodDecls; + bool mWantsDeferMethodDecls; + bool mLastHadComptimeRebuilds; + bool mHasComptimeRebuilds; bool mInInvalidState; float mCompletionPct; int mHSPreserveIdx; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index f338c2f1..477fd2ce 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -26,6 +26,7 @@ #include "BfSourceClassifier.h" #include "BfAutoComplete.h" #include "BfResolvePass.h" +#include "CeMachine.h" #pragma warning(pop) @@ -1850,6 +1851,7 @@ void BfContext::PreUpdateRevisedTypes() void BfContext::UpdateRevisedTypes() { BP_ZONE("BfContext::UpdateRevisedTypes"); + BfLogSysM("BfContext::UpdateRevisedTypes\n"); int wantPtrSize; if ((mCompiler->mOptions.mMachineType == BfMachineType_x86) | @@ -1889,6 +1891,9 @@ void BfContext::UpdateRevisedTypes() bool wantsDebugInfo = (mCompiler->mOptions.mEmitDebugInfo); Array defStateChangedQueue; + Array defEmitParentCheckQueue; + + Dictionary lastWriteTimeMap; // Do primary 'rebuild' scan for (auto type : mResolvedTypes) @@ -1917,20 +1922,8 @@ void BfContext::UpdateRevisedTypes() auto typeDef = typeInst->mTypeDef; - if (typeDef->mEmitParent != NULL) - { - if (typeDef->mDefState == BfTypeDef::DefState_Deleted) - { - typeInst->mTypeDef = typeDef->mEmitParent; - } - else - { - auto emitTypeDef = typeDef; - typeDef = typeDef->mEmitParent; - if (typeDef->mNextRevision != NULL) - emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; - } - } + if (typeDef->mEmitParent != NULL) + defEmitParentCheckQueue.Add(typeInst); if (typeDef->mProject->mDisabled) { @@ -1939,7 +1932,7 @@ void BfContext::UpdateRevisedTypes() } typeInst->mRebuildFlags = BfTypeRebuildFlag_None; - + if (typeDef->mIsPartial) { // This was a type that wasn't marked as partial before but now it is, so it doesn't need its own typedef @@ -1948,6 +1941,32 @@ void BfContext::UpdateRevisedTypes() continue; } + if (typeInst->mCeTypeInfo != NULL) + { + bool changed = false; + + for (auto& kv : typeInst->mCeTypeInfo->mRebuildMap) + { + mCompiler->mHasComptimeRebuilds = true; + if (kv.mKey.mKind == CeRebuildKey::Kind_File) + { + String* keyPtr = NULL; + uint64* valuePtr = NULL; + if (lastWriteTimeMap.TryAdd(kv.mKey.mString, &keyPtr, &valuePtr)) + { + *valuePtr = BfpFile_GetTime_LastWrite(kv.mKey.mString.c_str()); + } + if (*valuePtr != kv.mValue.mInt) + changed = true; + } + } + + if (changed) + { + RebuildType(typeInst); + } + } + if ((typeInst->mHotTypeData != NULL) && (!mCompiler->IsHotCompile())) { if (typeInst->mHotTypeData->GetLatestVersion()->mDeclHotCompileIdx != 0) @@ -2042,6 +2061,31 @@ void BfContext::UpdateRevisedTypes() } } + for (auto typeInst : defEmitParentCheckQueue) + { + if (typeInst->IsDeleting()) + continue; + auto typeDef = typeInst->mTypeDef; + if (typeDef->mEmitParent != NULL) + { + if (typeDef->mDefState == BfTypeDef::DefState_Deleted) + { + BfLogSysM("Type %p typeDef %p deleted, setting to emitParent %p\n", typeInst, typeDef, typeDef->mEmitParent); + typeInst->mTypeDef = typeDef->mEmitParent; + } + else + { + auto emitTypeDef = typeDef; + typeDef = typeDef->mEmitParent; + if (typeDef->mNextRevision != NULL) + { + BfLogSysM("Type %p typeDef %p emitparent %p has next revision, setting emittedDirty\n", typeInst, emitTypeDef, typeDef); + emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; + } + } + } + } + // { AutoCrit autoCrit(mSystem->mDataLock); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index a7750009..bb2dd1f5 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4919,7 +4919,10 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(targetSrc))) { if (autoComplete->mIsGetDefinition) - autoComplete->SetDefinitionLocation(basePropDef->GetRefNode(), true); + { + //NOTE: passing 'force=true' in here causes https://github.com/beefytech/Beef/issues/1064 + autoComplete->SetDefinitionLocation(basePropDef->GetRefNode()); + } autoComplete->mDefProp = basePropDef; autoComplete->mDefType = baseTypeInst->mTypeDef; } @@ -5407,7 +5410,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* return result; } else - { + { auto val = mModule->GetDefaultTypedValue(returnType, true, (GetStructRetIdx(methodInstance) != -1) ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value); if (val.mKind == BfTypedValueKind_Addr) val.mKind = BfTypedValueKind_RestrictedTempAddr; @@ -6973,7 +6976,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu filePath = mModule->mCurFilePosition.mFileInstance->mParser->mFileName; argValue = BfTypedValue(mModule->GetStringObjectValue(filePath), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); - } + } else if (strcmp(globalVar->mName, "#CallerFileName") == 0) { String filePath = ""; @@ -6990,6 +6993,24 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu argValue = BfTypedValue(mModule->GetStringObjectValue(GetFileDir(filePath)), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); } + else if (strcmp(globalVar->mName, "#CallerTypeName") == 0) + { + String typeName = ""; + if (mModule->mCurTypeInstance != NULL) + typeName = mModule->TypeToString(mModule->mCurTypeInstance); + argValue = BfTypedValue(mModule->GetStringObjectValue(typeName), + mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); + } + else if (strcmp(globalVar->mName, "#CallerType") == 0) + { + auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef); + BfType* type = mModule->mCurTypeInstance; + if (type != NULL) + { + mModule->AddDependency(type, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); + argValue = BfTypedValue(mModule->CreateTypeDataRef(type), typeType); + } + } else if (strcmp(globalVar->mName, "#CallerMemberName") == 0) { String memberName = ""; @@ -7095,7 +7116,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (methodRefType->WantsDataPassedAsSplat(dataIdx)) SplatArgs(lookupVal, irArgs); else + { + if (lookupVal.mType->IsComposite()) + lookupVal = mModule->MakeAddressable(lookupVal, false); irArgs.push_back(lookupVal.mValue); + } } } @@ -10182,6 +10207,17 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) if ((fieldResult) || (mPropDef != NULL)) { + if (mResultFieldInstance != NULL) + { + auto autoComplete = GetAutoComplete(); + if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(identifierNode))) + { + auto fieldDef = mResultFieldInstance->GetFieldDef(); + if (fieldDef != NULL) + autoComplete->SetDefinitionLocation(fieldDef->GetRefNode()); + } + } + mResult = fieldResult; PerformAssignment(assignExpr, true, BfTypedValue()); mResult = BfTypedValue(); @@ -11423,7 +11459,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI BfMethodInstance* methodRefMethodInst = methodRefType->mMethodRef; BF_ASSERT(methodRefMethodInst == methodInstance); - + auto paramType = methodInstance->GetParamType(paramIdx); int dataIdx = methodRefType->GetDataIdxFromParamIdx(paramIdx); @@ -11462,9 +11498,8 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI lookupVal = mModule->LoadValue(lookupVal); return lookupVal; } - } - BF_ASSERT(methodRefTarget.IsAddr()); - if (paramType->IsComposite()) + } + if ((paramType->IsComposite()) && (methodRefTarget.IsAddr())) return BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(methodRefTarget.mValue, 0, dataIdx), paramType, true); return BfTypedValue(mModule->ExtractValue(methodRefTarget, dataIdx), paramType); } @@ -11922,8 +11957,8 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) if (bindResult.mTarget.IsSplat()) target = mModule->AggregateSplat(bindResult.mTarget, &bindResult.mIRArgs[0]); else - target = mModule->LoadValue(bindResult.mTarget); - + target = bindResult.mTarget; + mModule->mBfIRBuilder->CreateStore(target.mValue, elemPtr); mResult = BfTypedValue(methodRefPtr, methodRefType, true); @@ -14525,8 +14560,10 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { if (typeInstance->IsObject()) { + bool hasRealtimeLeakCheck = (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck) && (!IsComptime()); + bool wantsCtorClear = true; - if (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck) + if (hasRealtimeLeakCheck) { // Dbg_ObjectAlloc clears internally so we don't need to call CtorClear for those if ((!isStackAlloc) && (!allocTarget.mCustomAllocator) && (allocTarget.mScopedInvocationTarget == NULL)) @@ -14548,7 +14585,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } } - if ((!mModule->mIsComptimeModule) && (isStackAlloc) && (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck)) + if ((!mModule->mIsComptimeModule) && (isStackAlloc) && (hasRealtimeLeakCheck)) { BfMethodInstance* markMethod = mModule->GetRawMethodByName(mModule->mContext->mBfObjectType, "GCMarkMembers"); BF_ASSERT(markMethod != NULL); @@ -14750,7 +14787,7 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN if (attributeDirective != NULL) { - auto customAttrs = mModule->GetCustomAttributes(attributeDirective, BfAttributeTargets_Alloc, true, &allocTarget.mCaptureInfo); + auto customAttrs = mModule->GetCustomAttributes(attributeDirective, BfAttributeTargets_Alloc, BfGetCustomAttributesFlags_AllowNonConstArgs, &allocTarget.mCaptureInfo); if (customAttrs != NULL) { for (auto& attrib : customAttrs->mAttributes) @@ -19750,7 +19787,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) auto indexType = (BfPrimitiveType*)indexArgument.mType; - if (!mModule->mSystem->DoesLiteralFit(indexType->mTypeDef->mTypeCode, sizedArrayType->mElementCount)) + if (!mModule->mSystem->DoesLiteralFit(indexType->mTypeDef->mTypeCode, (int64)sizedArrayType->mElementCount)) { // We need to upsize the index so we can compare it against the larger elementCount indexType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); @@ -22427,6 +22464,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mModule->GetPrimitiveType(BfTypeCode_Boolean)); return; + default: + break; } } @@ -22438,6 +22477,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL auto primType = (BfPrimitiveType*)resultType; if (primType->mTypeDef->mTypeCode == BfTypeCode_Boolean) { + bool passThrough = false; switch (binaryOp) { case BfBinaryOp_Equality: @@ -22464,16 +22504,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateXor(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; + case BfBinaryOp_Compare: + passThrough = true; + break; default: if (mModule->PreFail()) mModule->Fail("Invalid operation for booleans", opToken); break; } - return; + if (!passThrough) + return; } } - if ((!resultType->IsIntegral()) && (!resultType->IsFloat())) + if ((!resultType->IsIntegralOrBool()) && (!resultType->IsFloat())) { if (mModule->PreFail()) mModule->Fail(StrFormat("Cannot perform operation on type '%s'", mModule->TypeToString(resultType).c_str()), opToken); @@ -22578,7 +22622,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpGTE(convLeftValue, convRightValue, resultType->IsSigned()), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; - case BfBinaryOp_Compare: + case BfBinaryOp_Compare: { auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); if ((convLeftValue.IsConst()) && (convRightValue.IsConst())) @@ -22599,7 +22643,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->GetConstValue(0, mModule->GetPrimitiveType(BfTypeCode_IntPtr)), intType); } } - else if ((resultType->IsIntegral()) && (resultType->mSize < intType->mSize)) + else if ((resultType->IsIntegralOrBool()) && (resultType->mSize < intType->mSize)) { auto leftIntValue = mModule->mBfIRBuilder->CreateNumericCast(convLeftValue, resultType->IsSigned(), BfTypeCode_IntPtr); auto rightIntValue = mModule->mBfIRBuilder->CreateNumericCast(convRightValue, resultType->IsSigned(), BfTypeCode_IntPtr); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 95307c23..701a3a75 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2627,9 +2627,13 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine) BfMethodInstance* methodInstance = methodRefType->mMethodRef; String name = "_BF_MethodRef_"; - name += BfTypeUtils::HashEncode64(methodInstance->mIdHash).c_str(); - if (wantDIData) + if (methodInstance != NULL) + name += BfTypeUtils::HashEncode64(methodInstance->mIdHash).c_str(); + + BF_ASSERT(methodInstance != NULL); + + if ((wantDIData) && (methodInstance != NULL)) { auto typeDeclaration = methodInstance->GetOwner()->mTypeDef->mTypeDeclaration; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 760f6c68..86c767d4 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3913,7 +3913,7 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance* if (isLet || isVar) fieldType = GetPrimitiveType(BfTypeCode_Var); else - fieldType = ResolveTypeRef(fieldDef->mTypeRef); + fieldType = ResolveTypeRef(fieldDef->mTypeRef,BfPopulateType_Identity, BfResolveTypeRefFlag_AllowInferredSizedArray); if (fieldType == NULL) fieldType = mContext->mBfObjectType; } @@ -4297,7 +4297,7 @@ BfTypedValue BfModule::GetFieldInitializerValue(BfFieldInstance* fieldInstance, int ceExecuteId = -1; if (mCompiler->mCEMachine != NULL) ceExecuteId = mCompiler->mCEMachine->mExecuteId; - + BfTypeState typeState; typeState.mType = mCurTypeInstance; typeState.mCurTypeDef = fieldDef->mDeclaringType; @@ -6368,7 +6368,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin FieldFlags_Const = 0x40, FieldFlags_SpecialName = 0x80, FieldFlags_EnumPayload = 0x100, - FieldFlags_EnumDiscriminator = 0x200 + FieldFlags_EnumDiscriminator = 0x200, + FieldFlags_EnumCase = 0x400 }; if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) @@ -6434,6 +6435,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Static); if (fieldDef->mIsConst) fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Const); + if (fieldDef->IsEnumCaseEntry()) + fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_EnumCase); int customAttrIdx = _HandleCustomAttrs(fieldInstance->mCustomAttributes); BfIRValue constValue; @@ -7787,9 +7790,16 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS } } + if (checkArgType->IsPointer()) + { + auto ptrType = (BfPointerType*)checkArgType; + checkArgType = ptrType->mElementType; + } + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_New) != 0) { bool canAlloc = false; + if (auto checkTypeInst = checkArgType->ToTypeInstance()) { if (checkTypeInst->IsObjectOrStruct()) @@ -7857,13 +7867,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS } if ((genericParamInst->mInterfaceConstraints.IsEmpty()) && (genericParamInst->mOperatorConstraints.IsEmpty()) && (genericParamInst->mTypeConstraint == NULL)) - return true; - - if (checkArgType->IsPointer()) - { - auto ptrType = (BfPointerType*)checkArgType; - checkArgType = ptrType->mElementType; - } + return true; if (genericParamInst->mTypeConstraint != NULL) { @@ -8469,10 +8473,10 @@ void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, boo mBfIRBuilder->PopulateType(typedValue.mType); auto vObjectAddr = mBfIRBuilder->CreateInBoundsGEP(typedValue.mValue, 0, 0); bool isAutocomplete = mCompiler->IsAutocomplete(); - + BfIRValue vDataRef; if (!isAutocomplete) - { + { vDataRef = GetClassVDataPtr(typeInstance); } @@ -11143,8 +11147,11 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf } } -void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, bool allowNonConstArgs, BfCaptureInfo* captureInfo) +void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, BfGetCustomAttributesFlags flags, BfCaptureInfo* captureInfo) { + bool allowNonConstArgs = (flags & BfGetCustomAttributesFlags_AllowNonConstArgs) != 0; + bool keepConstsInModule = (flags & BfGetCustomAttributesFlags_KeepConstsInModule) != 0; + if (!mCompiler->mHasRequiredTypes) return; @@ -11388,7 +11395,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType, BfConstResolveFlag_NoActualizeValues); if (result) { - CurrentAddToConstHolder(result.mValue); + if (!keepConstsInModule) + CurrentAddToConstHolder(result.mValue); setField.mParam = result; customAttribute.mSetField.push_back(setField); } @@ -11450,7 +11458,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri if (!result.mValue.IsConst()) result = GetDefaultTypedValue(result.mType); BF_ASSERT(result.mType == propType); - CurrentAddToConstHolder(result.mValue); + if (!keepConstsInModule) + CurrentAddToConstHolder(result.mValue); setProperty.mParam = result; customAttribute.mSetProperties.push_back(setProperty); } @@ -11566,10 +11575,13 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri } // Move all those to the constHolder - for (auto& ctorArg : customAttribute.mCtorArgs) - { - if (ctorArg.IsConst()) - CurrentAddToConstHolder(ctorArg); + if (!keepConstsInModule) + { + for (auto& ctorArg : customAttribute.mCtorArgs) + { + if (ctorArg.IsConst()) + CurrentAddToConstHolder(ctorArg); + } } if (attributesDirective->mAttributeTargetSpecifier != NULL) @@ -11626,10 +11638,10 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri ValidateCustomAttributes(customAttributes, attrTarget); } -BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs, BfCaptureInfo* captureInfo) +BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags, BfCaptureInfo* captureInfo) { BfCustomAttributes* customAttributes = new BfCustomAttributes(); - GetCustomAttributes(customAttributes, attributesDirective, attrType, allowNonConstArgs, captureInfo); + GetCustomAttributes(customAttributes, attributesDirective, attrType, flags, captureInfo); return customAttributes; } @@ -11834,7 +11846,7 @@ bool BfModule::TryGetConstString(BfIRConstHolder* constHolder, BfIRValue irValue BfStringPoolEntry* entry = NULL; if (mContext->mStringObjectIdMap.TryGetValue(stringId, &entry)) { - str = entry->mString; + str += entry->mString; } else { @@ -15479,7 +15491,11 @@ void BfModule::CreateDelegateInvokeMethod() mBfIRBuilder->AddBlock(doneBB); mBfIRBuilder->SetInsertPoint(doneBB); - if ((mCurMethodInstance->mReturnType->IsValuelessType()) || + if (mCurMethodInstance->mReturnType->IsVar()) + { + // Do nothing + } + else if ((mCurMethodInstance->mReturnType->IsValuelessType()) || ((!mIsComptimeModule) && (mCurMethodInstance->GetStructRetIdx() != -1))) { mBfIRBuilder->CreateRetVoid(); @@ -18477,6 +18493,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) { BP_ZONE_F("BfModule::ProcessMethod %s", BP_DYN_STR(methodInstance->mMethodDef->mName.c_str())); + if (mIsComptimeModule) + { + BF_ASSERT(!mCompiler->IsAutocomplete()); + } + if (mAwaitingInitFinish) FinishInit(); @@ -21547,6 +21568,10 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) } } } + + auto delegateInfo = typeInstance->GetDelegateInfo(); + if ((delegateInfo != NULL) && (methodInstance->mMethodDef->mMethodType == BfMethodType_Normal) && (methodInstance->mMethodDef->mName == "Invoke")) + methodInstance->mCallingConvention = delegateInfo->mCallingConvention; } void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& mangledName, bool isTemporaryFunc, bool* outIsIntrinsic) @@ -22157,6 +22182,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (resolvedReturnType == NULL) resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); + + if ((methodDef->mIsReadOnly) && (!resolvedReturnType->IsRef())) + { + if (auto methodDeclaration = BfNodeDynCast(methodInstance->mMethodDef->mMethodDeclaration)) + if (methodDeclaration->mReadOnlySpecifier != NULL) + Fail("Readonly specifier is only valid on 'ref' return types", methodDeclaration->mReadOnlySpecifier); + } } else { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index efa5ae8f..0be8a8b2 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1383,6 +1383,13 @@ enum BfDeferredBlockFlags BfDeferredBlockFlag_MoveNewBlocksToEnd = 8, }; +enum BfGetCustomAttributesFlags +{ + BfGetCustomAttributesFlags_None = 0, + BfGetCustomAttributesFlags_AllowNonConstArgs = 1, + BfGetCustomAttributesFlags_KeepConstsInModule = 2 +}; + class BfVDataExtEntry { public: @@ -1567,8 +1574,8 @@ public: BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false); void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget); - void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); - BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); + void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); + BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef); void FinishAttributeState(BfAttributeState* attributeState); void ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize); @@ -1744,13 +1751,15 @@ public: void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext); BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, const StringImpl& src); void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode); - void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet foundAttributes); + void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred); void CEMixin(BfAstNode* refNode, const StringImpl& src); - void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind); - void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers); + void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred); + void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred); void DoCEEmit(BfMethodInstance* methodInstance); void DoPopulateType_TypeAlias(BfTypeInstance* typeAlias); - void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType); + void DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred); void DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data); static BfModule* GetModuleFor(BfType* type); void DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance); @@ -1844,6 +1853,7 @@ public: void CheckIdentifierFixit(BfAstNode* node); void TypeRefNotFound(BfTypeReference* typeRef, const char* appendName = NULL); bool ValidateTypeWildcard(BfTypeReference* 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* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 70fa7133..33eb2122 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -704,23 +704,13 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) void BfModule::AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType) { - auto fieldTypeInstance = fieldType->ToTypeInstance(); + auto depFlag = fieldType->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData; + AddDependency(fieldType, typeInstance, depFlag); - if (fieldTypeInstance == NULL) - { - auto underlyingType = fieldType->GetUnderlyingType(); - if (underlyingType != NULL) - AddFieldDependency(typeInstance, fieldInstance, underlyingType); - return; - } - - auto depFlag = fieldTypeInstance->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData; - AddDependency(fieldTypeInstance, typeInstance, depFlag); - - if ((fieldTypeInstance->IsStruct()) && (fieldTypeInstance->IsGenericTypeInstance())) + if ((fieldType->IsStruct()) && (fieldType->IsGenericTypeInstance())) { // When we're a generic struct, our data layout can depend on our generic parameters as well - auto genericTypeInstance = (BfTypeInstance*)fieldTypeInstance; + auto genericTypeInstance = (BfTypeInstance*)fieldType; for (auto typeGenericArg : genericTypeInstance->mGenericTypeInfo->mTypeGenericArguments) AddFieldDependency(typeInstance, fieldInstance, typeGenericArg); } @@ -1189,7 +1179,10 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType } } - BfLogSysM("PopulateType: %p %s populateType:%d ResolveOnly:%d Reified:%d AutoComplete:%d Ctx:%p Mod:%p TypeId:%d\n", resolvedTypeRef, TypeToString(resolvedTypeRef, BfTypeNameFlags_None).c_str(), populateType, mCompiler->mIsResolveOnly, mIsReified, mCompiler->IsAutocomplete(), mContext, this, resolvedTypeRef->mTypeId); + BfTypeDef* typeDef = NULL; + if (typeInstance != NULL) + typeDef = typeInstance->mTypeDef; + BfLogSysM("PopulateType: %p %s populateType:%d ResolveOnly:%d Reified:%d AutoComplete:%d Ctx:%p Mod:%p TypeId:%d TypeDef:%p\n", resolvedTypeRef, TypeToString(resolvedTypeRef, BfTypeNameFlags_None).c_str(), populateType, mCompiler->mIsResolveOnly, mIsReified, mCompiler->IsAutocomplete(), mContext, this, resolvedTypeRef->mTypeId, typeDef); BF_ASSERT(!resolvedTypeRef->IsDeleting()); } @@ -2078,7 +2071,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn { for (int ifaceTypeId : ceEmitContext->mInterfaces) typeInstance->mCeTypeInfo->mPendingInterfaces.Add(ifaceTypeId); - + if (ceEmitContext->mEmitData.IsEmpty()) return; @@ -2133,7 +2126,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn } } -void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes) +void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred) { BfTypeInstance* iComptimeTypeApply = NULL; for (auto& customAttribute : customAttributes->mAttributes) @@ -2166,12 +2159,8 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* if (!attrType->IsValuelessType()) args.Add(attrVal); args.Add(mBfIRBuilder->CreateTypeOf(typeInstance)); - - //TESTING -// mCompiler->mCEMachine->ReleaseContext(ceContext); -// ceContext = mCompiler->mCEMachine->AllocContext(); -// ceContext->mMemory.mSize = ceContext->mMemory.mAllocSize; - + + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) @@ -2182,7 +2171,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* // We populated before we could finish AssertErrorState(); } - else + else { auto owner = methodInstance->GetOwner(); int typeId = owner->mTypeId; @@ -2302,18 +2291,18 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code) FinishCEParseContext(refNode, mCurTypeInstance, &ceParseContext); } -void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind) +void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred) { HashSet foundAttributes; if (ceEmitContext != NULL) { if (typeInstance->mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes, underlyingTypeDeferred); for (auto& fieldInstance : typeInstance->mFieldInstances) { if (fieldInstance.mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes, underlyingTypeDeferred); } } @@ -2355,7 +2344,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* if (onCompileAttribute == NULL) continue; - HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes, underlyingTypeDeferred); if (onCompileAttribute->mCtorArgs.size() < 1) continue; @@ -2383,6 +2372,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* mCompiler->mCEMachine->mCurEmitContext = ceEmitContext; } + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto methodInstance = GetRawMethodInstanceAtIdx(typeInstance, methodDef->mIdx); auto result = mCompiler->mCEMachine->Call(methodDef->GetRefNode(), this, methodInstance, {}, (CeEvalFlags)(CeEvalFlags_PersistantError | CeEvalFlags_DeferIfNotOnlyError), NULL); @@ -2451,11 +2441,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* // } } -void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers) +void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred) { CeEmitContext ceEmitContext; ceEmitContext.mType = typeInstance; - ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit); + ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit, underlyingTypeDeferred); hadNewMembers = (typeInstance->mTypeDef->mEmitParent != NULL); if (ceEmitContext.mFailed) @@ -2609,7 +2599,7 @@ void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericType } void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) -{ +{ SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeAlias); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL); SetAndRestoreValue prevMethodState(mCurMethodState, NULL); @@ -2685,6 +2675,176 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) DoPopulateType_SetGenericDependencies(typeAlias); } +void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType) +{ + if (typeInstance->IsEnum()) + { + int64 min = 0; + int64 max = 0; + + bool isFirst = true; + + if (typeInstance->mTypeInfoEx == NULL) + typeInstance->mTypeInfoEx = new BfTypeInfoEx(); + + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) + { + if (fieldInstance->mConstIdx == -1) + continue; + + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); + + if (isFirst) + { + min = constant->mInt64; + max = constant->mInt64; + isFirst = false; + } + else + { + min = BF_MIN(constant->mInt64, min); + max = BF_MAX(constant->mInt64, max); + } + } + } + + typeInstance->mTypeInfoEx->mMinValue = min; + typeInstance->mTypeInfoEx->mMaxValue = max; + + if (underlyingTypeDeferred) + { + BfTypeCode typeCode; + + if ((min >= -0x80) && (max <= 0x7F)) + typeCode = BfTypeCode_Int8; + else if ((min >= 0) && (max <= 0xFF)) + typeCode = BfTypeCode_UInt8; + else if ((min >= -0x8000) && (max <= 0x7FFF)) + typeCode = BfTypeCode_Int16; + else if ((min >= 0) && (max <= 0xFFFF)) + typeCode = BfTypeCode_UInt16; + else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) + typeCode = BfTypeCode_Int32; + else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) + typeCode = BfTypeCode_UInt32; + else + typeCode = BfTypeCode_Int64; + + if (typeCode != BfTypeCode_Int64) + { + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + if (fieldInstance->mConstIdx == -1) + continue; + if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) + continue; + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); + fieldInstance->mConstIdx = newConstant.mId; + } + } + + BfType* underlyingType = GetPrimitiveType(typeCode); + auto fieldInstance = &typeInstance->mFieldInstances.back(); + fieldInstance->mResolvedType = underlyingType; + fieldInstance->mDataSize = underlyingType->mSize; + + typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; + + typeInstance->mSize = underlyingType->mSize; + typeInstance->mAlign = underlyingType->mAlign; + typeInstance->mInstSize = underlyingType->mSize; + typeInstance->mInstAlign = underlyingType->mAlign; + + typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); + } + } + else + { + BF_ASSERT(!underlyingTypeDeferred); + } + + if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) + { + typeInstance->mAlign = unionInnerType->mAlign; + + int lastTagId = -1; + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) + { + BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); + lastTagId = -fieldInstance->mDataIdx - 1; + } + } + + auto fieldInstance = &typeInstance->mFieldInstances.back(); + //BF_ASSERT(fieldInstance->mResolvedType == NULL); + BfPrimitiveType* discriminatorType; + if (lastTagId > 0x7FFFFFFF) // HOW? + discriminatorType = GetPrimitiveType(BfTypeCode_Int64); + else if (lastTagId > 0x7FFF) + discriminatorType = GetPrimitiveType(BfTypeCode_Int32); + else if (lastTagId > 0x7F) + discriminatorType = GetPrimitiveType(BfTypeCode_Int16); + else + discriminatorType = GetPrimitiveType(BfTypeCode_Int8); + fieldInstance->mResolvedType = discriminatorType; + + fieldInstance->mDataOffset = unionInnerType->mSize; + fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator + if (!typeInstance->mIsPacked) + { + if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) + { + fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); + fieldInstance->mDataIdx++; // Add room for explicit padding + } + } + + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); + typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; + + typeInstance->mInstSize = typeInstance->mSize; + typeInstance->mInstAlign = typeInstance->mAlign; + + if (dataMemberHashCtx != NULL) + { + dataMemberHashCtx->Mixin(unionInnerType->mTypeId); + dataMemberHashCtx->Mixin(discriminatorType->mTypeId); + } + + typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry + } +} + +void BfModule::DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred) +{ + if (!typeInstance->IsEnum()) + return; + if ((!underlyingTypeDeferred) && (!typeInstance->IsPayloadEnum())) + return; + if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL)) + return; + + BfType* unionInnerType = NULL; + if (typeInstance->mIsUnion) + { + SetAndRestoreValue prevResolveKind(mContext->mCurTypeState->mResolveKind, BfTypeState::ResolveKind_UnionInnerType); + unionInnerType = typeInstance->GetUnionInnerType(); + } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, NULL, unionInnerType); +} + void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType) { if (populateType == BfPopulateType_Identity) @@ -3732,6 +3892,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (typeInstance->mTypeDef != innerTypeInst->mTypeDef) { // Rebuild with proper typedef (generally from inner type comptime emission) + BfLogSysM("Boxed type %p overriding typeDef to %p from inner type %p\n", typeInstance, innerTypeInst->mTypeDef, innerType); typeInstance->mTypeDef = innerTypeInst->mTypeDef; DoPopulateType(resolvedTypeRef, populateType); return; @@ -4056,7 +4217,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_CETypeInit; bool hadNewMembers = false; - DoCEEmit(typeInstance, hadNewMembers); + DoCEEmit(typeInstance, hadNewMembers, underlyingTypeDeferred); if (typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) typeInstance->mDefineState = BfTypeDefineState_CEPostTypeInit; @@ -4660,7 +4821,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_Defined; if (!typeInstance->IsBoxed()) { - ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone); + ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone, underlyingTypeDeferred); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) return; } @@ -4831,151 +4992,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy BfLogSysM("Setting underlying type %p %d\n", typeInstance, underlyingTypeDeferred); } - if (typeInstance->IsEnum()) - { - int64 min = 0; - int64 max = 0; - - bool isFirst = true; - - if (typeInstance->mTypeInfoEx == NULL) - typeInstance->mTypeInfoEx = new BfTypeInfoEx(); - - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) - { - if (fieldInstance->mConstIdx == -1) - continue; - - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); - - if (isFirst) - { - min = constant->mInt64; - max = constant->mInt64; - isFirst = false; - } - else - { - min = BF_MIN(constant->mInt64, min); - max = BF_MAX(constant->mInt64, max); - } - } - } - - typeInstance->mTypeInfoEx->mMinValue = min; - typeInstance->mTypeInfoEx->mMaxValue = max; - - if (underlyingTypeDeferred) - { - BfTypeCode typeCode; - - if ((min >= -0x80) && (max <= 0x7F)) - typeCode = BfTypeCode_Int8; - else if ((min >= 0) && (max <= 0xFF)) - typeCode = BfTypeCode_UInt8; - else if ((min >= -0x8000) && (max <= 0x7FFF)) - typeCode = BfTypeCode_Int16; - else if ((min >= 0) && (max <= 0xFFFF)) - typeCode = BfTypeCode_UInt16; - else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) - typeCode = BfTypeCode_Int32; - else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) - typeCode = BfTypeCode_UInt32; - else - typeCode = BfTypeCode_Int64; - - if (typeCode != BfTypeCode_Int64) - { - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - if (fieldInstance->mConstIdx == -1) - continue; - if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) - continue; - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); - fieldInstance->mConstIdx = newConstant.mId; - } - } - - underlyingType = GetPrimitiveType(typeCode); - auto fieldInstance = &typeInstance->mFieldInstances.back(); - fieldInstance->mResolvedType = underlyingType; - fieldInstance->mDataSize = underlyingType->mSize; - - typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; - - typeInstance->mSize = underlyingType->mSize; - typeInstance->mAlign = underlyingType->mAlign; - typeInstance->mInstSize = underlyingType->mSize; - typeInstance->mInstAlign = underlyingType->mAlign; - - typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); - } - } - else - { - BF_ASSERT(!underlyingTypeDeferred); - } - - if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) - { - typeInstance->mAlign = unionInnerType->mAlign; - - int lastTagId = -1; - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) - { - BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); - lastTagId = -fieldInstance->mDataIdx - 1; - } - } - - auto fieldInstance = &typeInstance->mFieldInstances.back(); - BF_ASSERT(fieldInstance->mResolvedType == NULL); - BfPrimitiveType* discriminatorType; - if (lastTagId > 0x7FFFFFFF) // HOW? - discriminatorType = GetPrimitiveType(BfTypeCode_Int64); - else if (lastTagId > 0x7FFF) - discriminatorType = GetPrimitiveType(BfTypeCode_Int32); - else if (lastTagId > 0x7F) - discriminatorType = GetPrimitiveType(BfTypeCode_Int16); - else - discriminatorType = GetPrimitiveType(BfTypeCode_Int8); - fieldInstance->mResolvedType = discriminatorType; - - fieldInstance->mDataOffset = unionInnerType->mSize; - fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator - if (!isPacked) - { - if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) - { - fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); - fieldInstance->mDataIdx++; // Add room for explicit padding - } - } - - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); - typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; - - typeInstance->mInstSize = typeInstance->mSize; - typeInstance->mInstAlign = typeInstance->mAlign; - - dataMemberHashCtx.Mixin(unionInnerType->mTypeId); - dataMemberHashCtx.Mixin(discriminatorType->mTypeId); - - typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry - } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, &dataMemberHashCtx, unionInnerType); if (!typeInstance->IsBoxed()) { @@ -5633,7 +5650,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } } - if (typeInstance->mTypeDef->mProject->mTargetType == BfTargetType_BeefTest) + if (methodInstance->mMethodDef->mDeclaringType->mProject->mTargetType == BfTargetType_BeefTest) { if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mTestAttributeTypeDef))) { @@ -7556,7 +7573,7 @@ BfTypeDef* BfModule::ResolveGenericInstanceDef(BfGenericInstanceTypeRef* generic { BfTypeLookupError error; error.mRefNode = typeRef; - BfTypeDef* typeDef = FindTypeDef(typeRef, NULL, &error, numGenericParams); + BfTypeDef* typeDef = FindTypeDef(typeRef, NULL, &error, numGenericParams, resolveFlags); if (typeDef != NULL) { BfAutoComplete* autoComplete = NULL; @@ -7587,6 +7604,8 @@ BfTypeDef* BfModule::ResolveGenericInstanceDef(BfGenericInstanceTypeRef* generic if (typeRef->IsA()) { String findName = typeRef->ToString(); + if ((resolveFlags & BfResolveTypeRefFlag_Attribute) != 0) + findName += "Attribute"; if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance())) { auto genericTypeInst = (BfTypeInstance*)mCurTypeInstance; @@ -9341,6 +9360,28 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod return BfTypedValue(); } +void BfModule::GetDelegateTypeRefAttributes(BfDelegateTypeRef* delegateTypeRef, BfCallingConvention& callingConvention) +{ + if (delegateTypeRef->mAttributes == NULL) + return; + + BfCaptureInfo captureInfo; + auto customAttributes = GetCustomAttributes(delegateTypeRef->mAttributes, (BfAttributeTargets)(BfAttributeTargets_DelegateTypeRef | BfAttributeTargets_FunctionTypeRef), BfGetCustomAttributesFlags_KeepConstsInModule); + if (customAttributes != NULL) + { + auto linkNameAttr = customAttributes->Get(mCompiler->mCallingConventionAttributeTypeDef); + if (linkNameAttr != NULL) + { + if (linkNameAttr->mCtorArgs.size() == 1) + { + auto constant = mBfIRBuilder->GetConstant(linkNameAttr->mCtorArgs[0]); + if (constant != NULL) + callingConvention = (BfCallingConvention)constant->mInt32; + } + } + } +} + BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags, int numGenericArgs) { BP_ZONE("BfModule::ResolveTypeRef"); @@ -10078,11 +10119,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } BfResolvedTypeSet::LookupContext lookupCtx; - lookupCtx.mResolveFlags = (BfResolveTypeRefFlags)(resolveFlags & (BfResolveTypeRefFlag_NoCreate | BfResolveTypeRefFlag_IgnoreLookupError | BfResolveTypeRefFlag_DisallowComptime | BfResolveTypeRefFlag_AllowInferredSizedArray)); + lookupCtx.mResolveFlags = (BfResolveTypeRefFlags)(resolveFlags & (BfResolveTypeRefFlag_NoCreate | BfResolveTypeRefFlag_IgnoreLookupError | + BfResolveTypeRefFlag_DisallowComptime | BfResolveTypeRefFlag_AllowInferredSizedArray | BfResolveTypeRefFlag_Attribute)); lookupCtx.mRootTypeRef = typeRef; lookupCtx.mRootTypeDef = typeDef; lookupCtx.mModule = this; BfResolvedTypeSet::Entry* resolvedEntry = NULL; + if (auto delegateTypeRef = BfNodeDynCastExact(typeRef)) + GetDelegateTypeRefAttributes(delegateTypeRef, lookupCtx.mCallingConvention); + auto inserted = mContext->mResolvedTypes.Insert(typeRef, &lookupCtx, &resolvedEntry); if (resolvedEntry == NULL) @@ -10355,7 +10400,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula BfTypeVector genericArgs; BfType* type = NULL; - BfTypeDef* typeDef = ResolveGenericInstanceDef(genericTypeInstRef, &type); + BfTypeDef* typeDef = ResolveGenericInstanceDef(genericTypeInstRef, &type, resolveFlags); if(ambiguousTypeDef != NULL) ShowAmbiguousTypeError(typeRef, typeDef, ambiguousTypeDef); if (typeDef == NULL) @@ -10542,8 +10587,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula wantGeneric = true; if (type->IsUnspecializedType()) isUnspecialized = true; - BF_ASSERT(!type->IsVar()); - + if (type->IsVar()) + { + mContext->mResolvedTypes.RemoveEntry(resolvedEntry); + return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); + } types.push_back(type); names.push_back(fieldName); } @@ -10834,7 +10882,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula dlgType->mIsUnspecializedTypeVariation = isUnspecialized; delegateType = dlgType; } - + + delegateInfo->mCallingConvention = lookupCtx.mCallingConvention; + Val128 hashContext; BfTypeDef* typeDef = new BfTypeDef(); @@ -13090,9 +13140,11 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf auto fromMethodInst = GetRawMethodByName(fromTypeInst, "Invoke", -1, true); auto toMethodInst = GetRawMethodByName(toTypeInst, "Invoke", -1, true); - + + auto toDelegateInfo = toTypeInst->GetDelegateInfo(); + if ((fromMethodInst != NULL) && (toMethodInst != NULL) && - (fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) && + (fromMethodInst->mCallingConvention == toMethodInst->mCallingConvention) && (fromMethodInst->mMethodDef->mIsMutating == toMethodInst->mMethodDef->mIsMutating) && (fromMethodInst->mReturnType == toMethodInst->mReturnType) && (fromMethodInst->GetParamCount() == toMethodInst->GetParamCount())) @@ -13673,6 +13725,25 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF str += "delegate "; else str += "function "; + + if (delegateInfo->mCallingConvention != BfCallingConvention_Unspecified) + { + str += "[CallingConvention("; + switch (delegateInfo->mCallingConvention) + { + case BfCallingConvention_Cdecl: + str += ".Cdecl"; + break; + case BfCallingConvention_Stdcall: + str += ".Stdcall"; + break; + case BfCallingConvention_Fastcall: + str += ".Fastcall"; + break; + } + str += ")] "; + } + DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides); str += "("; diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 0bcea9b5..49548b98 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -3800,13 +3800,14 @@ BF_EXPORT bool BF_CALLTYPE BfParser_Reduce(BfParser* bfParser, BfPassInstance* b } static Array gCharMapping; -BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping) +BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping, int maxCol) { BP_ZONE("BfParser_Reduce"); String& outString = *gTLStrReturn.Get(); outString.clear(); gCharMapping.Clear(); BfPrinter bfPrinter(bfParser->mRootNode, bfParser->mSidechannelRootNode, bfParser->mErrorRootNode); + bfPrinter.mMaxCol = maxCol; bfPrinter.mFormatStart = formatStart; bfPrinter.mFormatEnd = formatEnd; bfPrinter.mCharMapping = &gCharMapping; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index f30db3a9..39dcbbce 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -300,11 +300,8 @@ int BfPrinter::CalcOrigLineSpacing(BfAstNode* bfAstNode, int* lineStartIdx) void BfPrinter::WriteIgnoredNode(BfAstNode* node) { - if ((!mOutString.IsEmpty()) && (!isspace((uint8)mOutString[mOutString.mLength - 1]))) - { - Write(" "); - } - + bool startsWithSpace = false; + bool wasExpectingNewLine = mExpectingNewLine; mTriviaIdx = std::max(mTriviaIdx, node->GetTriviaStart()); @@ -315,12 +312,17 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) for (int i = mTriviaIdx; i < srcEnd; i++) { char c = astNodeSrc->mSrc[i]; + if ((i == mTriviaIdx) && (isspace((uint8)c))) + startsWithSpace = true; + if ((c == '\n') && (i < node->GetSrcStart())) crCount++; if (((c != ' ') && (c != '\t')) || (!mReformatting)) endIdx = i + 1; } + bool wantsPrefixSpace = (!mOutString.IsEmpty()) && (!isspace((uint8)mOutString[mOutString.mLength - 1])); + bool expectingNewLine = mNextStateModify.mWantNewLineIdx != mVirtualNewLineIdx; int startIdx = mTriviaIdx; @@ -333,7 +335,10 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) if ((origLineSpacing != -1) && (lineStart != -1)) { for (int i = 0; i < crCount; i++) + { Write("\n"); + wantsPrefixSpace = false; + } startIdx = node->GetSrcStart(); // Leave left-aligned preprocessor nodes if ((node->GetSourceData()->mSrc[node->GetSrcStart()] != '#') || (origLineSpacing > 0)) @@ -439,6 +444,10 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) bool emitChar = true; char c = astNodeSrc->mSrc[srcIdx]; + + if ((wantsPrefixSpace) && (isspace((uint8)c))) + wantsPrefixSpace = false; + if (c == '\n') { isNewLine = true; @@ -592,7 +601,12 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) } } - FlushIndent(); + if (wantsPrefixSpace) + { + mQueuedSpaceCount++; + wantsPrefixSpace = false; + } + FlushIndent(); for (int idx = startIdx; idx <= BF_MIN(srcIdx, endIdx - 1); idx++) { @@ -1038,6 +1052,8 @@ void BfPrinter::Visit(BfLabelableStatement* labelableStmt) void BfPrinter::Visit(BfCommentNode* commentNode) { WriteIgnoredNode(commentNode); + if (commentNode->mCommentKind == BfCommentKind_Line) + ExpectNewLine(); } void BfPrinter::Visit(BfPreprocesorIgnoredSectionNode* preprocesorIgnoredSection) @@ -1569,8 +1585,9 @@ void BfPrinter::Visit(BfDelegateTypeRef* typeRef) VisitChild(typeRef->mTypeToken); ExpectSpace(); - VisitChild(typeRef->mReturnType); VisitChild(typeRef->mAttributes); + ExpectSpace(); + VisitChild(typeRef->mReturnType); VisitChild(typeRef->mOpenParen); for (int i = 0; i < (int)typeRef->mParams.size(); i++) diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index baa65d07..0164aad0 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -281,9 +281,52 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int* int endNode = -1; + bool failed = false; + // Return type auto checkNode = mVisitorPos.GetCurrent(); - if ((checkNode == NULL) || (!IsTypeReference(checkNode, BfToken_LParen, &endNode, couldBeExpr, isGenericType, isTuple))) + if (auto checkToken = BfNodeDynCast(checkNode)) + { + if (checkToken->mToken == BfToken_LBracket) + { + while (true) + { + mVisitorPos.mReadPos++; + checkNode = mVisitorPos.GetCurrent(); + if (checkNode == NULL) + { + failed = true; + break; + } + + if (BfNodeIsA(checkNode)) + { + failed = true; + break; + } + + if (checkToken = BfNodeDynCast(checkNode)) + { + if (checkToken->mToken == BfToken_RBracket) + { + mVisitorPos.mReadPos++; + checkNode = mVisitorPos.GetCurrent(); + break; + } + if ((checkToken->mToken != BfToken_Comma) && + (checkToken->mToken != BfToken_Dot) && + (checkToken->mToken != BfToken_LParen) && + (checkToken->mToken != BfToken_RParen)) + { + failed = true; + break; + } + } + } + } + } + + if ((failed) || (checkNode == NULL) || (!IsTypeReference(checkNode, BfToken_LParen, &endNode, couldBeExpr, isGenericType, isTuple))) { if (outEndNode != NULL) *outEndNode = endNode; @@ -4806,6 +4849,14 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF ReplaceNode(firstNode, delegateTypeRef); MEMBER_SET(delegateTypeRef, mTypeToken, tokenNode); + auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + if ((nextToken != NULL) && (nextToken->mToken == BfToken_LBracket)) + { + mVisitorPos.MoveNext(); + auto attribs = CreateAttributeDirective(nextToken); + MEMBER_SET_CHECKED(delegateTypeRef, mAttributes, attribs); + } + auto returnType = CreateTypeRefAfter(delegateTypeRef); MEMBER_SET_CHECKED(delegateTypeRef, mReturnType, returnType); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 26ba94bc..2512e290 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2664,6 +2664,8 @@ int BfArrayType::GetLengthBitCount() int BfMethodRefType::GetCaptureDataCount() { + if (mMethodRef == NULL) + return 0; return (int)mDataToParamIdx.size(); } @@ -3021,7 +3023,8 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfResolveTypeRefFlags resolveFlags = ctx->mResolveFlags; if ((flags & BfHashFlag_AllowGenericParamConstValue) != 0) resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_AllowGenericParamConstValue); - + if (!isHeadType) + resolveFlags = (BfResolveTypeRefFlags)(resolveFlags &~ BfResolveTypeRefFlag_Attribute); auto resolvedType = ctx->mModule->ResolveTypeRef(typeRef, BfPopulateType_Identity, resolveFlags); if (resolvedType == NULL) { @@ -3669,6 +3672,8 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) BfDelegateInfo* rhsDelegateInfo = rhs->GetDelegateInfo(); if (lhsInst->mTypeDef->mIsDelegate != rhsInst->mTypeDef->mIsDelegate) return false; + if (lhsDelegateInfo->mCallingConvention != rhsDelegateInfo->mCallingConvention) + return false; auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0]; auto rhsMethodDef = rhsInst->mTypeDef->mMethods[0]; @@ -3917,7 +3922,9 @@ bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfType return false; } - BfTypeDef* elementTypeDef = ctx->mModule->ResolveGenericInstanceDef(rhsGenericTypeInstRef); + BfTypeDef* elementTypeDef = ctx->mModule->ResolveGenericInstanceDef(rhsGenericTypeInstRef, NULL, ctx->mResolveFlags); + if (elementTypeDef == NULL) + return false; if (elementTypeDef->GetDefinition() != lhsGenericType->mTypeDef->GetDefinition()) return false; @@ -4088,8 +4095,16 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* if ((lhs->IsDelegate()) != rhsIsDelegate) return false; + + BfCallingConvention rhsCallingConvention = BfCallingConvention_Unspecified; + if (ctx->mRootTypeRef == rhsDelegateType) + rhsCallingConvention = ctx->mCallingConvention; + else + ctx->mModule->GetDelegateTypeRefAttributes(rhsDelegateType, rhsCallingConvention); + if (lhsDelegateInfo->mCallingConvention != rhsCallingConvention) + return false; if (!Equals(lhsDelegateInfo->mReturnType, rhsDelegateType->mReturnType, ctx)) - return false; + return false; bool isMutating = true; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 9b9a1321..ee281ccf 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -452,6 +452,7 @@ public: Array mParams; bool mHasExplicitThis; bool mHasVarArgs; + BfCallingConvention mCallingConvention; public: BfDelegateInfo() @@ -459,6 +460,7 @@ public: mReturnType = NULL; mHasExplicitThis = false; mHasVarArgs = false; + mCallingConvention = BfCallingConvention_Unspecified; } ~BfDelegateInfo() @@ -569,6 +571,7 @@ public: virtual bool IsBoolean() { return false; } virtual bool IsInteger() { return false; } virtual bool IsIntegral() { return false; } + virtual bool IsIntegralOrBool() { return false; } virtual bool IsIntPtr() { return false; } virtual bool IsSigned() { return false; } virtual bool IsSignedInt() { return false; } @@ -625,6 +628,7 @@ public: virtual bool IsValueTypeOrValueTypePtr() override { return true; } virtual bool IsBoolean() override { return mTypeDef->mTypeCode == BfTypeCode_Boolean; } virtual bool IsIntegral() override { return (mTypeDef->mTypeCode >= BfTypeCode_Int8) && (mTypeDef->mTypeCode <= BfTypeCode_Char32); } + virtual bool IsIntegralOrBool() override { return (mTypeDef->mTypeCode >= BfTypeCode_Boolean) && (mTypeDef->mTypeCode <= BfTypeCode_Char32); } virtual bool IsInteger() override { return (mTypeDef->mTypeCode >= BfTypeCode_Int8) && (mTypeDef->mTypeCode <= BfTypeCode_UIntUnknown); } virtual bool IsIntPtr() override { return (mTypeDef->mTypeCode == BfTypeCode_IntPtr) || (mTypeDef->mTypeCode == BfTypeCode_UIntPtr); } virtual bool IsIntPtrable() override @@ -1582,7 +1586,9 @@ enum BfAttributeTargets : int32 BfAttributeTargets_Delete = 0x80000, BfAttributeTargets_Alias = 0x100000, BfAttributeTargets_Block = 0x200000, - BfAttributeTargets_All = 0x3FFFFF + BfAttributeTargets_DelegateTypeRef = 0x400000, + BfAttributeTargets_FunctionTypeRef = 0x800000, + BfAttributeTargets_All = 0xFFFFFF }; enum BfAttributeFlags : int8 @@ -1823,23 +1829,7 @@ public: String mEmitData; }; -class BfCeTypeInfo -{ -public: - Dictionary mOnCompileMap; - Dictionary mTypeIFaceMap; - Array mPendingInterfaces; - Val128 mHash; - bool mFailed; - BfCeTypeInfo* mNext; - -public: - BfCeTypeInfo() - { - mFailed = false; - mNext = NULL; - } -}; +class BfCeTypeInfo; // Instance of struct or class class BfTypeInstance : public BfDependedType @@ -2526,6 +2516,7 @@ public: BfType* mRootResolvedType; Dictionary mResolvedTypeMap; BfResolveTypeRefFlags mResolveFlags; + BfCallingConvention mCallingConvention; bool mHadVar; bool mFailed; @@ -2540,6 +2531,7 @@ public: mFailed = false; mHadVar = false; mResolveFlags = BfResolveTypeRefFlag_None; + mCallingConvention = BfCallingConvention_Unspecified; } BfType* GetCachedResolvedType(BfTypeReference* typeReference); diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index a3bda91d..27fe5279 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3455,7 +3455,9 @@ void BfModule::VisitCodeBlock(BfBlock* block) } else if ((mCurMethodInstance->IsMixin()) && (mCurMethodState->mCurScope == &mCurMethodState->mHeadScope)) { - // Silently allow... + // Only in mixin definition - result ignored + CreateValueFromExpression(expr); + break; } else { @@ -3925,6 +3927,10 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt) { if (genericParamInst->mGenericParamFlags & (BfGenericParamFlag_Delete | BfGenericParamFlag_Var)) return; + if (genericParamInst->mGenericParamFlags & BfGenericParamFlag_StructPtr) + return; + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Struct) && (checkType->IsPointer())) + return; Fail(StrFormat("Must add 'where %s : delete' constraint to generic parameter to delete generic type '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), TypeToString(val.mType).c_str()), deleteStmt->mExpression); return; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index de407542..a9d869ec 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -498,7 +498,9 @@ BfImportKind BfMethodDef::GetImportKindFromPath(const StringImpl& filePath) { String fileExt = GetFileExtension(filePath); - if ((fileExt.Equals(".DLL", StringImpl::CompareKind_OrdinalIgnoreCase)) || + if ((fileExt.Equals(".DYLIB", StringImpl::CompareKind_OrdinalIgnoreCase)) || + (fileExt.Equals(".SO", StringImpl::CompareKind_OrdinalIgnoreCase)) || + (fileExt.Equals(".DLL", StringImpl::CompareKind_OrdinalIgnoreCase)) || (fileExt.Equals(".EXE", StringImpl::CompareKind_OrdinalIgnoreCase))) { return BfImportKind_Import_Dynamic; @@ -4159,11 +4161,12 @@ BF_EXPORT const char* BF_CALLTYPE BfSystem_GetNamespaceSearch(BfSystem* bfSystem return outString.c_str(); } -BF_EXPORT BfProject* BF_CALLTYPE BfSystem_CreateProject(BfSystem* bfSystem, const char* projectName) +BF_EXPORT BfProject* BF_CALLTYPE BfSystem_CreateProject(BfSystem* bfSystem, const char* projectName, const char* projectDir) { AutoCrit autoCrit(bfSystem->mDataLock); BfProject* bfProject = new BfProject(); bfProject->mName = projectName; + bfProject->mDirectory = projectDir; bfProject->mSystem = bfSystem; bfProject->mIdx = (int)bfSystem->mProjects.size(); bfSystem->mProjects.push_back(bfProject); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 1a4fbd93..4a0184c9 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1180,6 +1180,7 @@ public: BfSystem* mSystem; String mName; String mSafeName; + String mDirectory; Array mDependencies; BfTargetType mTargetType; BfCodeGenOptions mCodeGenOptions; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index b8054687..7b1ac835 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -5,7 +5,10 @@ #include "BfParser.h" #include "BfReducer.h" #include "BfExprEvaluator.h" +#include "BfResolvePass.h" #include "../Backend/BeIRCodeGen.h" +#include "BeefySysLib/platform/PlatformHelper.h" + extern "C" { #include "BeefySysLib/third_party/utf8proc/utf8proc.h" @@ -301,6 +304,24 @@ static int DoubleToString(double d, char* outStr) ////////////////////////////////////////////////////////////////////////// +CeInternalData::~CeInternalData() +{ + switch (mKind) + { + case Kind_File: + BfpFile_Release(mFile); + break; + case Kind_FindFileData: + BfpFindFileData_Release(mFindFileData); + break; + case Kind_Spawn: + BfpSpawn_Release(mSpawn); + break; + } +} + +////////////////////////////////////////////////////////////////////////// + CeFunction::~CeFunction() { BF_ASSERT(mId == -1); @@ -1261,6 +1282,12 @@ void CeBuilder::HandleParams() void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance) { SetAndRestoreValue prevMethodStateInConstEval(mCeMachine->mCeModule->mCurMethodState, NULL); + BfAutoComplete* prevAutoComplete = NULL; + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + { + prevAutoComplete = mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete; + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = NULL; + } auto irCodeGen = mCeMachine->mCeModule->mBfIRBuilder->mBeIRCodeGen; auto irBuilder = mCeMachine->mCeModule->mBfIRBuilder; @@ -1275,6 +1302,9 @@ void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true); irCodeGen->SetState(beState); irBuilder->SetState(irState); + + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = prevAutoComplete; } void CeBuilder::Build() @@ -1312,7 +1342,7 @@ void CeBuilder::Build() mCeMachine->mCeModule->mStaticFieldRefs.Clear(); int startFunctionCount = (int)beModule->mFunctions.size(); - ProcessMethod(methodInstance, &dupMethodInstance); + ProcessMethod(methodInstance, &dupMethodInstance); if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; @@ -2873,6 +2903,7 @@ CeContext::CeContext() mCeMachine = NULL; mReflectTypeIdOffset = -1; mExecuteId = -1; + mStackSize = -1; mCurTargetSrc = NULL; mHeap = new ContiguousHeap(); @@ -2886,6 +2917,7 @@ CeContext::CeContext() CeContext::~CeContext() { delete mHeap; + BF_ASSERT(mInternalDataMap.IsEmpty()); } BfError* CeContext::Fail(const StringImpl& error) @@ -2996,11 +3028,23 @@ BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) ////////////////////////////////////////////////////////////////////////// +void CeContext::AddRebuild(const CeRebuildKey& key, const CeRebuildValue& value) +{ + if (mCurModule == NULL) + return; + if (mCurModule->mCurTypeInstance == NULL) + return; + if (mCurModule->mCurTypeInstance->mCeTypeInfo == NULL) + mCurModule->mCurTypeInstance->mCeTypeInfo = new BfCeTypeInfo(); + mCurModule->mCurTypeInstance->mCeTypeInfo->mRebuildMap[key] = value; + mCurModule->mCompiler->mHasComptimeRebuilds = true; +} + uint8* CeContext::CeMalloc(int size) { #ifdef CE_ENABLE_HEAP auto heapRef = mHeap->Alloc(size); - auto ceAddr = BF_CE_STACK_SIZE + heapRef; + auto ceAddr = mStackSize + heapRef; int sizeDelta = (ceAddr + size) - mMemory.mSize; if (sizeDelta > 0) mMemory.GrowUninitialized(sizeDelta); @@ -3013,7 +3057,7 @@ uint8* CeContext::CeMalloc(int size) bool CeContext::CeFree(addr_ce addr) { #ifdef CE_ENABLE_HEAP - ContiguousHeap::AllocRef heapRef = addr - BF_CE_STACK_SIZE; + ContiguousHeap::AllocRef heapRef = addr - mStackSize; return mHeap->Free(heapRef); #else return true; @@ -3702,6 +3746,19 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType charPtr = (char*)(instData + ptrOffset); } } + else + { + int64 allocSizeVal = *(int64*)(instData + allocSizeOffset); + if ((allocSizeVal & 0x4000000000000000LL) != 0) + { + int32 ptrVal = *(int32*)(instData + ptrOffset); + charPtr = (char*)(ptrVal + memStart); + } + else + { + charPtr = (char*)(instData + ptrOffset); + } + } CE_CREATECONST_CHECKPTR(charPtr, lenVal); String str(charPtr, lenVal); @@ -4085,7 +4142,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns if (ceFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(ceFunction, NULL); - auto stackPtr = &mMemory[0] + BF_CE_STACK_SIZE; + auto stackPtr = &mMemory[0] + mStackSize; auto* memStart = &mMemory[0]; BfTypeInstance* thisType = methodInstance->GetOwner(); @@ -4107,6 +4164,23 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns allocThisSize += appendSizeConstant->mInt32; } + if (allocThisSize >= mStackSize / 4) + { + // Resize stack a reasonable size + mStackSize = BF_ALIGN(allocThisSize, 0x100000) + BF_CE_DEFAULT_STACK_SIZE; + int64 memSize = mStackSize + BF_CE_DEFAULT_HEAP_SIZE; + if (memSize > BF_CE_MAX_MEMORY) + { + Fail("Return value too large (>2GB)"); + return BfTypedValue(); + } + + if (memSize > mMemory.mSize) + mMemory.Resize(memSize); + stackPtr = &mMemory[0] + mStackSize; + memStart = &mMemory[0]; + } + stackPtr -= allocThisSize; auto allocThisPtr = stackPtr; memset(allocThisPtr, 0, allocThisSize); @@ -4123,6 +4197,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns { stackPtr -= ceModule->mSystem->mPtrSize; memset(stackPtr, 0, ceModule->mSystem->mPtrSize); + *(addr_ce*)(stackPtr) = (addr_ce)(allocThisInstAddr + thisType->mInstSize); allocAppendIdxAddr = stackPtr - memStart; } @@ -4256,7 +4331,14 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } BfType* usedReturnType = returnType; - BfIRValue constVal = CreateConstant(module, retPtr, returnType, &usedReturnType); + BfIRValue constVal; + if (returnType->IsObject()) + { + addr_ce retAddr = retPtr - memStart; + constVal = CreateConstant(module, (uint8*)&retAddr, returnType, &usedReturnType); + } + else + constVal = CreateConstant(module, retPtr, returnType, &usedReturnType); if (constVal) returnValue = BfTypedValue(constVal, usedReturnType); else @@ -4289,9 +4371,10 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } #define CE_CHECKALLOC(SIZE) \ - if ((SIZE < 0) || (uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY) \ + if ((SIZE < 0) || (SIZE >= 0x80000000LL) || ((uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY)) \ { \ - _Fail("Maximum memory size exceeded"); \ + _Fail("Maximum memory size exceeded (2GB)"); \ + return false; \ } // This check will fail for addresses < 64K (null pointer), or out-of-bounds @@ -4302,12 +4385,65 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns return false; \ } #define CE_CHECKADDR(ADDR, SIZE) \ - if (((ADDR) - 0x10000) + (SIZE) > (memSize - 0x10000)) \ + if (((ADDR) < 0x10000) || ((ADDR) + (SIZE) > memSize)) \ { \ _Fail("Access violation"); \ return false; \ } +#define CE_CHECKADDR_STR(STRNAME, ADDR) \ + { \ + addr_ce checkAddr = ADDR; \ + while (true) \ + { \ + if ((uintptr)checkAddr >= (uintptr)memSize) \ + { \ + break; \ + } \ + if (memStart[checkAddr] == 0) \ + { \ + CE_CHECKADDR(ADDR, checkAddr - ADDR + 1); \ + STRNAME = String::MakeRef((char*)memStart + ADDR, checkAddr - ADDR + 1); \ + break; \ + } \ + checkAddr++; \ + } \ + } + +#define CE_GET_INTERNAL(VAR, ID, KIND) \ + if (!mInternalDataMap.TryGetValue((int)ID, &VAR)) \ + { \ + _Fail("Invalid internal resource id"); \ + return false; \ + } \ + if (VAR->mKind != KIND) \ + { \ + _Fail("Invalid internal resource kind"); \ + return false; \ + } \ + if (VAR->mReleased) \ + { \ + _Fail("Resource already released"); \ + return false; \ + } + +#define CE_REMOVE_INTERNAL(VAR, ID, KIND) \ + if (!mInternalDataMap.Remove((int)ID, &VAR)) \ + { \ + _Fail("Invalid internal resource id"); \ + return false; \ + } \ + if (VAR->mKind != KIND) \ + { \ + _Fail("Invalid internal resource kind"); \ + return false; \ + } \ + if (VAR->mReleased) \ + { \ + _Fail("Resource already released"); \ + return false; \ + } + #define CE_GETINST(T) *((T*)(instPtr += sizeof(T)) - 1) #define CE_GETFRAME(T) *(T*)(framePtr + *((int32*)(instPtr += sizeof(int32)) - 1)) #define CEOP_BIN(OP, T) \ @@ -4422,7 +4558,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns instPtr = &ceFunction->mCode[0]; \ CE_CHECKSTACK(); -static void CeSetAddrVal(void* ptr, addr_ce val, int32 ptrSize) +static void CeSetAddrVal(void* ptr, int64 val, int32 ptrSize) { if (ptrSize == 4) *(int32*)(ptr) = (int32)val; @@ -4490,7 +4626,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } else if (checkFunction->mFunctionKind == CeFunctionKind_Malloc) { - int32 size = *(int32*)((uint8*)stackPtr + 4); + int64 size; + if (ptrSize == 4) + size = *(int32*)((uint8*)stackPtr + 4); + else + size = *(int64*)((uint8*)stackPtr + 8); CE_CHECKALLOC(size); uint8* ptr = CeMalloc(size); CeSetAddrVal(stackPtr + 0, ptr - memStart, ptrSize); @@ -4532,6 +4672,19 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* charPtr = (char*)(strInst + ptrOffset); } } + else + { + int64 allocSizeVal = *(int64*)(strInst + allocSizeOffset); + if ((allocSizeVal & 0x4000000000000000LL) != 0) + { + int32 ptrVal = *(int32*)(strInst + ptrOffset); + charPtr = (char*)(ptrVal + memStart); + } + else + { + charPtr = (char*)(strInst + ptrOffset); + } + } int32 ptrVal = *(int32*)(strInst + ptrOffset); @@ -4559,13 +4712,21 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) { - int32 intVal = *(int32*)((uint8*)stackPtr + 0); - OutputDebugStrF("Debug Val: %d\n", intVal); + if (ceModule->mSystem->mPtrSize == 4) + { + int32 intVal = *(int32*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %d %X\n", intVal, intVal); + } + else + { + int64 intVal = *(int64*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %lld %llX\n", intVal, intVal); + } } else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) { addr_ce objAddr = *(addr_ce*)((uint8*)stackPtr + ceModule->mSystem->mPtrSize); - CE_CHECKADDR(addr_ce, 4); + CE_CHECKADDR(objAddr, 4); int32 typeId = *(int32*)(objAddr + memStart); auto reflectType = GetReflectType(typeId); @@ -4911,7 +5072,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* addr_ce strAddr = *(addr_ce*)((uint8*)stackPtr + 8); addr_ce endAddr = *(addr_ce*)((uint8*)stackPtr + 8 + ptrSize); - addr_ce checkAddr = strAddr; + addr_ce checkAddr = strAddr; while (true) { if ((uintptr)checkAddr >= (uintptr)memSize) @@ -4921,10 +5082,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } if (memStart[checkAddr] == 0) break; + checkAddr++; } CE_CHECKADDR(strAddr, checkAddr - strAddr + 1); - char* strPtr = (char*)(memStart + strAddr); + char* strPtr = (char*)(memStart + strAddr); char** endPtr = NULL; if (endAddr != NULL) endPtr = (char**)(memStart + endAddr); @@ -4959,7 +5121,292 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* memcpy(memStart + strAddr, str, count + 1); result = count; } - else + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Close) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Close(internalData->mFile, (BfpFileResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Create) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce nameAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + int createKind = *(int*)((uint8*)stackPtr + ptrSize + ptrSize); + int createFlags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + 4); + int createFileAttrs = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + 4 + 4); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + 4 + 4 + 4); + + String path; + CE_CHECKADDR_STR(path, nameAddr); + CE_CHECKADDR(outResultAddr, 4); + + BfProject* activeProject = NULL; + auto activeTypeDef = mCurModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + activeProject = activeTypeDef->mProject; + if (activeProject != NULL) + path = GetAbsPath(path, activeProject->mDirectory); + + auto bfpFile = BfpFile_Create(path.c_str(), (BfpFileCreateKind)createKind, (BfpFileCreateFlags)createFlags, (BfpFileAttributes)createFileAttrs, (BfpFileResult*)(memStart + outResultAddr)); + if (bfpFile != NULL) + { + if ((createKind == BfpFileCreateKind_OpenExisting) || (createKind == BfpFileCreateKind_OpenAlways)) + { + auto timeStamp = BfpFile_GetTime_LastWrite(path.c_str()); + if (timeStamp != 0) + { + CeRebuildKey rebuildKey; + rebuildKey.mKind = CeRebuildKey::Kind_File; + rebuildKey.mString = path; + + CeRebuildValue rebuildValue; + rebuildValue.mInt = timeStamp; + + AddRebuild(rebuildKey, rebuildValue); + } + } + + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_File; + internalData->mFile = bfpFile; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(resultPtr, mCurHandleId, ptrSize); + } + else + CeSetAddrVal(resultPtr, 0, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Flush) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Flush(internalData->mFile); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_GetFileSize) + { + int64& result = *(int64*)((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 8); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + result = BfpFile_GetFileSize(internalData->mFile); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Read) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce bufferPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + intptr bufferSize = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + int timeoutMS = *(int32*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(bufferPtr, bufferSize); + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + int64 result = BfpFile_Read(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (BfpFileResult*)(memStart + outResultAddr)); + CeSetAddrVal(resultPtr, result, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Release) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + + CeInternalData* internalData = NULL; + CE_REMOVE_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + delete internalData; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Seek) + { + int64& result = *(int64*)((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 8); + int64 offset = *(int64*)((uint8*)stackPtr + 8 + ptrSize); + int seekKind = *(int*)((uint8*)stackPtr + 8 + ptrSize + 8); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + result = BfpFile_Seek(internalData->mFile, offset, (BfpFileSeekKind)seekKind); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Truncate) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Truncate(internalData->mFile, (BfpFileResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Write) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce bufferPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + intptr bufferSize = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + int timeoutMS = *(int32*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(bufferPtr, bufferSize); + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + int64 result = BfpFile_Write(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (outResultAddr == 0) ? NULL : (BfpFileResult*)(memStart + outResultAddr)); + CeSetAddrVal(resultPtr, result, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Create) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce targetPathAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce argsAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce workingDirAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + addr_ce envAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + int flags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize + 4); + + String targetPath; + CE_CHECKADDR_STR(targetPath, targetPathAddr); + String args; + if (argsAddr != 0) + CE_CHECKADDR_STR(args, argsAddr); + String workingDir; + if (workingDirAddr != 0) + CE_CHECKADDR_STR(workingDir, workingDirAddr); + String env; + if (envAddr != 0) + CE_CHECKADDR_STR(env, envAddr); + CE_CHECKADDR(outResultAddr, 4); + + if ((targetPath.Contains('/')) || (targetPath.Contains('\\'))) + { + BfProject* activeProject = NULL; + auto activeTypeDef = mCurModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + activeProject = activeTypeDef->mProject; + if (activeProject != NULL) + targetPath = GetAbsPath(targetPath, activeProject->mDirectory); + } + + auto bfpSpawn = BfpSpawn_Create(targetPath.c_str(), + (argsAddr == 0) ? NULL : args.c_str(), + (workingDirAddr == 0) ? NULL : workingDir.c_str(), + (envAddr == 0) ? NULL : env.c_str(), (BfpSpawnFlags)flags, (outResultAddr == 0) ? NULL : (BfpSpawnResult*)(memStart + outResultAddr)); + if (bfpSpawn != NULL) + { + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_Spawn; + internalData->mSpawn = bfpSpawn; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(resultPtr, mCurHandleId, ptrSize); + } + else + CeSetAddrVal(resultPtr, 0, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_GetStdHandles) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outStdInAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce outStdOutAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce outStdErrAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outStdInAddr, ptrSize); + CE_CHECKADDR(outStdOutAddr, ptrSize); + CE_CHECKADDR(outStdErrAddr, ptrSize); + + BfpFile* outStdIn = NULL; + BfpFile* outStdOut = NULL; + BfpFile* outStdErr = NULL; + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + BfpSpawn_GetStdHandles(internalData->mSpawn, + (outStdInAddr != 0) ? &outStdIn : NULL, + (outStdOutAddr != 0) ? &outStdOut : NULL, + (outStdErrAddr != 0) ? &outStdErr : NULL); + + auto _SetHandle = [&](addr_ce addr, BfpFile* file) + { + if (addr == 0) + return; + if (file != NULL) + { + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_File; + internalData->mFile = file; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(memStart + addr, mCurHandleId, ptrSize); + } + }; + + _SetHandle(outStdInAddr, outStdIn); + _SetHandle(outStdOutAddr, outStdOut); + _SetHandle(outStdErrAddr, outStdErr); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Kill) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + int exitCode = *(int*)((uint8*)stackPtr + ptrSize); + int killFlags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + BfpSpawn_Kill(internalData->mSpawn, exitCode, (BfpKillFlags)killFlags, (BfpSpawnResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Release) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + internalData->mReleased = true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_WaitFor) + { + bool& result = *(bool*)((uint8*)stackPtr + 0); + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 1); + int waitMS = *(int*)((uint8*)stackPtr + 1 + ptrSize); + addr_ce outExitCodeAddr = *(addr_ce*)((uint8*)stackPtr + 1 + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + 1 + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outExitCodeAddr, ptrSize); + if (outResultAddr != 0) + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + + int outExitCode = 0; + int timeLeft = waitMS; + do + { + if (*fastFinishPtr) + { + result = false; + break; + } + + int waitTime = 20; + if (timeLeft >= 0) + { + waitTime = BF_MIN(timeLeft, 20); + timeLeft -= waitTime; + } + + result = BfpSpawn_WaitFor(internalData->mSpawn, waitTime, &outExitCode, (outResultAddr == 0) ? NULL : (BfpSpawnResult*)(memStart + outResultAddr)); + if (result) + break; + if (waitTime == 0) + break; + } while (true); + *(int*)(memStart + outExitCodeAddr) = outExitCode; + } + else { Fail(_GetCurFrame(), StrFormat("Unable to invoke extern method '%s'", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); return false; @@ -4989,6 +5436,8 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* int callCount = 0; int instIdx = 0; + CE_CHECKSTACK(); + while (true) { if (*fastFinishPtr) @@ -5004,7 +5453,6 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } ++instIdx; - CeOp op = CE_GETINST(CeOp); switch (op) { @@ -5132,7 +5580,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* case CeOp_Malloc: { auto frameOfs = CE_GETINST(int32); - int32 size = CE_GETFRAME(int32); + int64 size; + if (ptrSize == 4) + size = CE_GETFRAME(int32); + else + size = CE_GETFRAME(int64); CE_CHECKALLOC(size); uint8* mem = CeMalloc(size); _FixVariables(); @@ -5580,7 +6032,12 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* auto valueType = bfType->ToTypeInstance(); if (valueType->mVirtualMethodTable.IsEmpty()) - ceModule->PopulateType(valueType, BfPopulateType_DataAndMethods); + ceModule->PopulateType(valueType, BfPopulateType_Full_Force); + if (valueType->mVirtualMethodTable.IsEmpty()) + { + _Fail("Empty virtual table"); + return false; + } auto methodInstance = (BfMethodInstance*)valueType->mVirtualMethodTable[virtualIdx].mImplementingMethod; auto callFunction = mCeMachine->GetPreparedFunction(methodInstance); @@ -5624,6 +6081,13 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* { if (iface.mInterfaceType == ifaceType) { + if (valueType->mInterfaceMethodTable.IsEmpty()) + ceModule->PopulateType(valueType, BfPopulateType_Full_Force); + if (valueType->mInterfaceMethodTable.IsEmpty()) + { + _Fail("Empty interface table"); + return false; + } methodInstance = valueType->mInterfaceMethodTable[iface.mStartInterfaceTableIdx + methodIdx].mMethodRef; break; } @@ -6338,6 +6802,8 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* _Fail("Unhandled op"); return false; } + + //BF_ASSERT(_CrtCheckMemory() != 0); } return true; @@ -6359,7 +6825,7 @@ CeMachine::CeMachine(BfCompiler* compiler) mCurBuilder = NULL; mPreparingFunction = NULL; - mCurEmitContext = NULL; + mCurEmitContext = NULL; mAppendAllocInfo = NULL; mTempParser = NULL; @@ -6893,6 +7359,34 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) { if (methodDef->mName == "BfpSystem_GetTimeStamp") ceFunction->mFunctionKind = CeFunctionKind_BfpSystem_GetTimeStamp; + else if (methodDef->mName == "BfpFile_Close") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Close; + else if (methodDef->mName == "BfpFile_Create") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Create; + else if (methodDef->mName == "BfpFile_Flush") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Flush; + else if (methodDef->mName == "BfpFile_GetFileSize") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_GetFileSize; + else if (methodDef->mName == "BfpFile_Read") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Read; + else if (methodDef->mName == "BfpFile_Release") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Release; + else if (methodDef->mName == "BfpFile_Seek") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Seek; + else if (methodDef->mName == "BfpFile_Truncate") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Truncate; + else if (methodDef->mName == "BfpFile_Write") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Write; + else if (methodDef->mName == "BfpSpawn_Create") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Create; + else if (methodDef->mName == "BfpSpawn_GetStdHandles") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_GetStdHandles; + else if (methodDef->mName == "BfpSpawn_Kill") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Kill; + else if (methodDef->mName == "BfpSpawn_Release") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Release; + else if (methodDef->mName == "BfpSpawn_WaitFor") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_WaitFor; } else if (owner->IsInstanceOf(mCeModule->mCompiler->mChar32TypeDef)) { @@ -6926,45 +7420,45 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) { if (methodDef->mName == "Abs") ceFunction->mFunctionKind = CeFunctionKind_Math_Abs; - if (methodDef->mName == "Acos") + else if (methodDef->mName == "Acos") ceFunction->mFunctionKind = CeFunctionKind_Math_Acos; - if (methodDef->mName == "Asin") + else if (methodDef->mName == "Asin") ceFunction->mFunctionKind = CeFunctionKind_Math_Asin; - if (methodDef->mName == "Atan") + else if (methodDef->mName == "Atan") ceFunction->mFunctionKind = CeFunctionKind_Math_Atan; - if (methodDef->mName == "Atan2") + else if (methodDef->mName == "Atan2") ceFunction->mFunctionKind = CeFunctionKind_Math_Atan2; - if (methodDef->mName == "Ceiling") + else if (methodDef->mName == "Ceiling") ceFunction->mFunctionKind = CeFunctionKind_Math_Ceiling; - if (methodDef->mName == "Cos") + else if (methodDef->mName == "Cos") ceFunction->mFunctionKind = CeFunctionKind_Math_Cos; - if (methodDef->mName == "Cosh") + else if (methodDef->mName == "Cosh") ceFunction->mFunctionKind = CeFunctionKind_Math_Cosh; - if (methodDef->mName == "Exp") + else if (methodDef->mName == "Exp") ceFunction->mFunctionKind = CeFunctionKind_Math_Exp; - if (methodDef->mName == "Floor") + else if (methodDef->mName == "Floor") ceFunction->mFunctionKind = CeFunctionKind_Math_Floor; - if (methodDef->mName == "Log") + else if (methodDef->mName == "Log") ceFunction->mFunctionKind = CeFunctionKind_Math_Log; - if (methodDef->mName == "Log10") + else if (methodDef->mName == "Log10") ceFunction->mFunctionKind = CeFunctionKind_Math_Log10; - if (methodDef->mName == "Mod") + else if (methodDef->mName == "Mod") ceFunction->mFunctionKind = CeFunctionKind_Math_Mod; - if (methodDef->mName == "Pow") + else if (methodDef->mName == "Pow") ceFunction->mFunctionKind = CeFunctionKind_Math_Pow; - if (methodDef->mName == "Round") + else if (methodDef->mName == "Round") ceFunction->mFunctionKind = CeFunctionKind_Math_Round; - if (methodDef->mName == "Sin") + else if (methodDef->mName == "Sin") ceFunction->mFunctionKind = CeFunctionKind_Math_Sin; - if (methodDef->mName == "Sinh") + else if (methodDef->mName == "Sinh") ceFunction->mFunctionKind = CeFunctionKind_Math_Sinh; - if (methodDef->mName == "Sqrt") + else if (methodDef->mName == "Sqrt") ceFunction->mFunctionKind = CeFunctionKind_Math_Sqrt; - if (methodDef->mName == "Tan") + else if (methodDef->mName == "Tan") ceFunction->mFunctionKind = CeFunctionKind_Math_Tan; - if (methodDef->mName == "Tanh") + else if (methodDef->mName == "Tanh") ceFunction->mFunctionKind = CeFunctionKind_Math_Tanh; - } + } ceFunction->mInitializeState = CeFunction::InitializeState_Initialized; return; @@ -7214,11 +7708,13 @@ CeContext* CeMachine::AllocContext() ceContext->mMemory.Reserve(BF_CE_INITIAL_MEMORY); } - ceContext->mCurEmitContext = mCurEmitContext; - mCurEmitContext = NULL; + ceContext->mCurEmitContext = mCurEmitContext; + mCurEmitContext = NULL; mExecuteId++; - ceContext->mMemory.Resize(BF_CE_STACK_SIZE); + ceContext->mStackSize = BF_CE_DEFAULT_STACK_SIZE; + ceContext->mMemory.Resize(ceContext->mStackSize); ceContext->mExecuteId = mExecuteId; + ceContext->mCurHandleId = 0; return ceContext; } @@ -7234,9 +7730,12 @@ void CeMachine::ReleaseContext(CeContext* ceContext) ceContext->mStaticFieldMap.Clear(); ceContext->mHeap->Clear(BF_CE_MAX_CARRYOVER_HEAP); ceContext->mReflectTypeIdOffset = -1; - mCurEmitContext = ceContext->mCurEmitContext; - ceContext->mCurEmitContext = NULL; + mCurEmitContext = ceContext->mCurEmitContext; + ceContext->mCurEmitContext = NULL; mContextList.Add(ceContext); + for (auto kv : ceContext->mInternalDataMap) + delete kv.mValue; + ceContext->mInternalDataMap.Clear(); } BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags, BfType* expectingType) @@ -7246,3 +7745,5 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns ReleaseContext(ceContext); return result; } + + diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index ca36f4b0..f58aa3ab 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -264,6 +264,37 @@ public: } }; +class CeInternalData +{ +public: + enum Kind + { + Kind_None, + Kind_File, + Kind_FindFileData, + Kind_Spawn + }; + +public: + Kind mKind; + bool mReleased; + + union + { + BfpFile* mFile; + BfpFindFileData* mFindFileData; + BfpSpawn* mSpawn; + }; + + CeInternalData() + { + mKind = Kind_None; + mReleased = false; + } + + ~CeInternalData(); +}; + enum CeFunctionKind { CeFunctionKind_NotSet, @@ -294,6 +325,21 @@ enum CeFunctionKind CeFunctionKind_EmitMethodExit, CeFunctionKind_EmitMixin, + CeFunctionKind_BfpFile_Close, + CeFunctionKind_BfpFile_Create, + CeFunctionKind_BfpFile_Flush, + CeFunctionKind_BfpFile_GetFileSize, + CeFunctionKind_BfpFile_Read, + CeFunctionKind_BfpFile_Release, + CeFunctionKind_BfpFile_Seek, + CeFunctionKind_BfpFile_Truncate, + CeFunctionKind_BfpFile_Write, + CeFunctionKind_BfpSpawn_Create, + CeFunctionKind_BfpSpawn_GetStdHandles, + CeFunctionKind_BfpSpawn_Kill, + CeFunctionKind_BfpSpawn_Release, + CeFunctionKind_BfpSpawn_WaitFor, + CeFunctionKind_BfpSystem_GetTimeStamp, CeFunctionKind_Sleep, @@ -328,7 +374,7 @@ enum CeFunctionKind CeFunctionKind_Math_Sinh, CeFunctionKind_Math_Sqrt, CeFunctionKind_Math_Tan, - CeFunctionKind_Math_Tanh, + CeFunctionKind_Math_Tanh, }; class CeConstStructFixup @@ -501,10 +547,11 @@ public: } }; -#define BF_CE_STACK_SIZE 4*1024*1024 -#define BF_CE_INITIAL_MEMORY BF_CE_STACK_SIZE + 128*1024 -#define BF_CE_MAX_MEMORY 128*1024*1024 -#define BF_CE_MAX_CARRYOVER_MEMORY BF_CE_STACK_SIZE * 2 +#define BF_CE_DEFAULT_STACK_SIZE 4*1024*1024 +#define BF_CE_DEFAULT_HEAP_SIZE 128*1024 +#define BF_CE_INITIAL_MEMORY BF_CE_DEFAULT_STACK_SIZE + BF_CE_DEFAULT_HEAP_SIZE +#define BF_CE_MAX_MEMORY 0x7FFFFFFF +#define BF_CE_MAX_CARRYOVER_MEMORY BF_CE_DEFAULT_STACK_SIZE * 2 #define BF_CE_MAX_CARRYOVER_HEAP 1024*1024 enum CeOperandInfoKind @@ -683,12 +730,40 @@ public: BfIRValue mAppendSizeValue; }; +class CeRebuildKey +{ +public: + enum Kind + { + Kind_None, + Kind_File + }; + +public: + Kind mKind; + String mString; + + bool operator==(const CeRebuildKey& other) const + { + return (mKind == other.mKind) && (mString == other.mString); + } +}; + +class CeRebuildValue +{ +public: + union + { + uint64 mInt; + }; +}; + class CeEmitContext { public: - BfType* mType; + BfType* mType; BfMethodInstance* mMethodInstance; - Array mInterfaces; + Array mInterfaces; String mEmitData; String mExitEmitData; bool mFailed; @@ -706,6 +781,25 @@ public: } }; +class BfCeTypeInfo +{ +public: + Dictionary mOnCompileMap; + Dictionary mTypeIFaceMap; + Array mPendingInterfaces; + Dictionary mRebuildMap; + Val128 mHash; + bool mFailed; + BfCeTypeInfo* mNext; + +public: + BfCeTypeInfo() + { + mFailed = false; + mNext = NULL; + } +}; + class CeContext { public: @@ -719,19 +813,21 @@ public: ContiguousHeap* mHeap; Array mCallStack; Array mMemory; + int mStackSize; Dictionary mStringMap; Dictionary mReflectMap; Dictionary mConstDataMap; HashSet mStaticCtorExecSet; Dictionary mStaticFieldMap; - Dictionary mMemToCtxMap; + Dictionary mInternalDataMap; + int mCurHandleId; BfMethodInstance* mCurMethodInstance; BfType* mCurExpectingType; BfAstNode* mCurTargetSrc; BfModule* mCurModule; CeFrame* mCurFrame; - CeEmitContext* mCurEmitContext; + CeEmitContext* mCurEmitContext; public: CeContext(); @@ -740,6 +836,7 @@ public: BfError* Fail(const StringImpl& error); BfError* Fail(const CeFrame& curFrame, const StringImpl& error); + void AddRebuild(const CeRebuildKey& key, const CeRebuildValue& value); uint8* CeMalloc(int size); bool CeFree(addr_ce addr); addr_ce CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr); @@ -791,7 +888,7 @@ public: CeAppendAllocInfo* mAppendAllocInfo; CeContext* mCurContext; - CeEmitContext* mCurEmitContext; + CeEmitContext* mCurEmitContext; CeBuilder* mCurBuilder; CeFunction* mPreparingFunction; @@ -838,3 +935,15 @@ public: }; NS_BF_END + +namespace std +{ + template <> + struct hash + { + size_t operator()(const Beefy::CeRebuildKey& key) const + { + return BeefHash()(key.mString) ^ (size_t)key.mKind; + } + }; +} \ No newline at end of file diff --git a/IDEHelper/Profiler.cpp b/IDEHelper/Profiler.cpp index 1cca8c3c..8749cd2b 100644 --- a/IDEHelper/Profiler.cpp +++ b/IDEHelper/Profiler.cpp @@ -8,12 +8,12 @@ typedef LONG KPRIORITY; USING_NS_BF_DBG; -enum SYSTEM_INFORMATION_CLASS +enum SYSTEM_INFORMATION_CLASS { SystemProcessInformation = 5 }; // SYSTEM_INFORMATION_CLASS -struct CLIENT_ID +struct CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; @@ -81,14 +81,14 @@ struct SYSTEM_PROCESS_INFORMATION SYSTEM_THREAD Threads[1]; }; -typedef NTSTATUS(NTAPI *NtQuerySystemInformation_t)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +typedef NTSTATUS(NTAPI* NtQuerySystemInformation_t)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NtQuerySystemInformation_t NtQuerySystemInformation = NULL; static HMODULE ntdll = NULL; DbgProfiler::DbgProfiler(WinDebugger* debugger) : mShutdownEvent(true) { mDebugger = debugger; - mIsRunning = false; + mIsRunning = false; mWantsClear = false; mSamplesPerSecond = 1000; @@ -101,6 +101,13 @@ DbgProfiler::DbgProfiler(WinDebugger* debugger) : mShutdownEvent(true) mEndTick = 0; mDebugger->AddProfiler(this); + + mIdleSymbolNames.Add("ZwDelayExecution"); + mIdleSymbolNames.Add("ZwWaitForWorkViaWorkerFactory"); + mIdleSymbolNames.Add("NtWaitForAlertByThreadId"); + mIdleSymbolNames.Add("NtWaitForSingleObject"); + mIdleSymbolNames.Add("NtWaitForMultipleObjects"); + mIdleSymbolNames.Add("ZwRemoveIoCompletion"); } DbgProfiler::~DbgProfiler() @@ -113,14 +120,14 @@ DbgProfiler::~DbgProfiler() } static SYSTEM_PROCESS_INFORMATION* CaptureProcessInfo() -{ +{ WCHAR path[MAX_PATH]; GetSystemDirectory(path, MAX_PATH); - wcscat(path, L"\\ntdll.dll"); - ntdll = GetModuleHandle(path); + wcscat(path, L"\\ntdll.dll"); + ntdll = GetModuleHandle(path); if (ntdll == NULL) return NULL; - NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(ntdll, "NtQuerySystemInformation"); + NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(ntdll, "NtQuerySystemInformation"); uint allocSize = 1024; uint8* data = NULL; @@ -134,7 +141,7 @@ static SYSTEM_PROCESS_INFORMATION* CaptureProcessInfo() if (status != STATUS_INFO_LENGTH_MISMATCH) return (SYSTEM_PROCESS_INFORMATION*)data; - + allocSize = wantSize + 4096; delete data; } @@ -148,8 +155,8 @@ void DbgProfiler::DoClear() delete val.mProcId; } -ProfileProcId* DbgProfiler::Get(const StringImpl& str) -{ +ProfileProcId* DbgProfiler::Get(const StringImpl& str, bool* outIsNew) +{ ProfileProdIdEntry checkEntry; checkEntry.mProcId = (ProfileProcId*)&str; @@ -158,11 +165,16 @@ ProfileProcId* DbgProfiler::Get(const StringImpl& str) { auto procId = new ProfileProcId(); procId->mProcName = str; - entryPtr->mProcId = procId; + procId->mIsIdle = false; + entryPtr->mProcId = procId; + if (outIsNew != NULL) + *outIsNew = true; return procId; } else { + if (outIsNew != NULL) + *outIsNew = false; return entryPtr->mProcId; } } @@ -170,7 +182,7 @@ ProfileProcId* DbgProfiler::Get(const StringImpl& str) void DbgProfiler::ThreadProc() { //TODO: Do timing smarter, handle delays and slow stack traces and stuff - + //timeBeginPeriod(1); BF_ASSERT(mTotalVirtualSamples == 0); @@ -184,7 +196,7 @@ void DbgProfiler::ThreadProc() uint32 accumMS = 0; int totalWait = 0; - int totalWait2 = 0; + int totalWait2 = 0; int iterations = 0; HashSet idleThreadSet; @@ -218,9 +230,11 @@ void DbgProfiler::ThreadProc() iterations++; DWORD startTick0 = timeGetTime(); idleThreadSet.Clear(); - + SYSTEM_PROCESS_INFORMATION* processData = NULL; - std::unique_ptr ptrDelete(processData); + std::unique_ptr ptrDelete(processData); + + //processData = CaptureProcessInfo(); auto curProcessData = processData; while (true) @@ -235,6 +249,7 @@ void DbgProfiler::ThreadProc() auto& threadInfo = curProcessData->Threads[threadIdx]; if ((threadInfo.State == StateWait) || (threadInfo.State == StateTerminated)) idleThreadSet.Add((int)(intptr)threadInfo.ClientId.UniqueThread); + break; } } @@ -242,12 +257,12 @@ void DbgProfiler::ThreadProc() break; curProcessData = (SYSTEM_PROCESS_INFORMATION*)((intptr)curProcessData + curProcessData->NextEntryOffset); } - + if (mShutdownEvent.WaitFor(0)) { break; } - + DWORD tickNow = timeGetTime(); accumMS += (int)(tickNow - prevSampleTick); prevSampleTick = tickNow; @@ -284,21 +299,21 @@ void DbgProfiler::ThreadProc() mTotalVirtualSamples += curSampleCount; mTotalActualSamples++; - + int threadIdx = 0; while (true) - { + { int startTick = timeGetTime(); - AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); - - if (mDebugger->mRunState != RunState_Running) - break; + AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); + + if (mDebugger->mRunState != RunState_Running) + break; if (threadIdx >= mDebugger->mThreadList.size()) break; - auto thread = mDebugger->mThreadList[threadIdx]; + auto thread = mDebugger->mThreadList[threadIdx]; if ((mTargetThreadId > 0) && (thread->mThreadId != mTargetThreadId)) { @@ -321,20 +336,22 @@ void DbgProfiler::ThreadProc() profileThreadInfo = *profileThreadInfoPtr; } - profileThreadInfo->mTotalSamples += curSampleCount; - bool isThreadIdle = idleThreadSet.Contains(thread->mThreadId); + profileThreadInfo->mTotalSamples += curSampleCount; + if (isThreadIdle) + profileThreadInfo->mTotalIdleSamples += curSampleCount; + mDebugger->mActiveThread = thread; - - ::SuspendThread(thread->mHThread); + + ::SuspendThread(thread->mHThread); CPURegisters registers; mDebugger->PopulateRegisters(®isters); int stackSize = 0; - for (int stackIdx = 0 ; stackIdx < maxStackTrace; stackIdx++) - { + for (int stackIdx = 0; stackIdx < maxStackTrace; stackIdx++) + { auto pc = registers.GetPC(); if (pc <= 0xFFFF) { @@ -353,7 +370,7 @@ void DbgProfiler::ThreadProc() ProfileAddrEntry* insertedProfileEntry = AddToSet(mProfileAddrEntrySet, stackTrace, stackSize); if (insertedProfileEntry->mEntryIdx == -1) - { + { insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1' mPendingProfileEntries.Add(*insertedProfileEntry); } @@ -365,7 +382,7 @@ void DbgProfiler::ThreadProc() entryIdx = -entryIdx; profileThreadInfo->mProfileAddrEntries.push_back(entryIdx); } - + ::ResumeThread(thread->mHThread); int elapsedTime = timeGetTime() - startTick; @@ -379,7 +396,7 @@ void DbgProfiler::ThreadProc() } } - mIsRunning = false; + mIsRunning = false; mEndTick = BFTickCount(); } @@ -394,7 +411,7 @@ void DbgProfiler::Start() BF_ASSERT(!mIsRunning); mNeedsProcessing = true; - mIsRunning = true; + mIsRunning = true; auto thread = BfpThread_Create(ThreadProcThunk, (void*)this, 128 * 1024, BfpThreadCreateFlag_StackSizeReserve); BfpThread_Release(thread); } @@ -439,22 +456,25 @@ String DbgProfiler::GetThreadList() for (auto threadId : mThreadIdList) { auto threadInfo = mThreadInfo[threadId]; - result += StrFormat("%d\t%s\n", threadId, threadInfo->mName.c_str()); + int cpuUsage = 0; + if (threadInfo->mTotalSamples > 0) + cpuUsage = 100 - (threadInfo->mTotalIdleSamples * 100 / threadInfo->mTotalSamples); + result += StrFormat("%d\t%d\t%s\n", threadId, cpuUsage, threadInfo->mName.c_str()); } return result; } void DbgProfiler::AddEntries(String& str, Array& procEntries, int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc) -{ +{ struct _QueuedEntry { int mRangeIdx; int mRangeEnd; - int mStackIdx; + int mStackIdx; }; Array<_QueuedEntry> workQueue; - + auto _AddEntries = [&](int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc) { int selfSampleCount = 0; @@ -521,7 +541,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, _QueuedEntry entry; entry.mRangeIdx = rangeStart; entry.mRangeEnd = rangeEnd; - entry.mStackIdx = stackIdx; + entry.mStackIdx = stackIdx; workQueue.Add(entry); }; _AddEntries(rangeStart, rangeEnd, stackIdx, findProc); @@ -529,7 +549,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, while (!workQueue.IsEmpty()) { auto& entry = workQueue.back(); - + bool addedChild = false; while (entry.mRangeIdx < entry.mRangeEnd) { @@ -539,7 +559,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, entry.mRangeIdx++; continue; } - + int nextStackIdx = entry.mStackIdx + 1; auto nextFindProc = procEntry->mData[procEntry->mSize - 1 - nextStackIdx]; _AddEntries(entry.mRangeIdx, entry.mRangeEnd, nextStackIdx, nextFindProc); @@ -552,7 +572,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, if (entry.mStackIdx != -1) str += "-\n"; workQueue.pop_back(); - } + } } } @@ -608,7 +628,10 @@ void DbgProfiler::HandlePendingEntries() symbolName += StrFormat("0x%@", addr); } - procId = Get(symbolName); + bool isNew = false; + procId = Get(symbolName, &isNew); + if (isNew) + procId->mIsIdle = mIdleSymbolNames.Contains(symbolName); } if (reverse) @@ -640,11 +663,11 @@ void DbgProfiler::Process() AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); mNeedsProcessing = false; - + int time = mTotalActiveSamplingMS; BF_ASSERT(mProfileAddrEntries.IsEmpty()); - + mProfileAddrEntries.Resize(mProfileAddrEntrySet.size() + 1); for (auto& val : mProfileAddrEntrySet) mProfileAddrEntries[val.mEntryIdx] = &val; @@ -654,16 +677,35 @@ void DbgProfiler::Process() for (auto& val : mProfileProcEntrySet) mProfileProcEntries[val.mEntryIdx] = &val; + for (auto threadKV : mThreadInfo) + { + auto threadInfo = threadKV.mValue; + + for (auto addrEntryIdx : threadInfo->mProfileAddrEntries) + { + if (addrEntryIdx < 0) + { + addrEntryIdx = -addrEntryIdx; + } + + int procEntryIdx = mProfileAddrToProcMap[addrEntryIdx]; + auto procEntry = mProfileProcEntries[procEntryIdx]; + + auto curProc = procEntry->mData[0]; + if (curProc->mIsIdle) + threadInfo->mTotalIdleSamples++; + } + } } String DbgProfiler::GetCallTree(int threadId, bool reverse) -{ +{ if (mNeedsProcessing) Process(); AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); - BF_ASSERT(!mIsRunning); + BF_ASSERT(!mIsRunning); Array procEntries; @@ -714,10 +756,10 @@ String DbgProfiler::GetCallTree(int threadId, bool reverse) int idleTicks = totalSampleCount - totalActiveSampleCount; if (idleTicks != 0) str += StrFormat("\t%d\t0\n-\n", idleTicks); - + AddEntries(str, procEntries, 0, (int)procEntries.size(), -1, NULL); - - str += "-\n"; + + str += "-\n"; //BF_ASSERT(childSampleCount == totalSampleCount); diff --git a/IDEHelper/Profiler.h b/IDEHelper/Profiler.h index b8a0a64a..018fa548 100644 --- a/IDEHelper/Profiler.h +++ b/IDEHelper/Profiler.h @@ -67,6 +67,7 @@ class ProfileProcId { public: String mProcName; + bool mIsIdle; }; class ProfileProdIdEntry @@ -104,12 +105,14 @@ class ProfileThreadInfo public: Array mProfileAddrEntries; int mTotalSamples; + int mTotalIdleSamples; String mName; public: ProfileThreadInfo() { mTotalSamples = 0; + mTotalIdleSamples = 0; } }; @@ -143,6 +146,7 @@ public: Dictionary mProcMap; // Keyed on either DwSubprogram or DwSymbol. Multiple pointers can reference the same ProfileProcId (in the case of inlined functions, for example) HashSet mUniqueProcSet; + HashSet mIdleSymbolNames; public: void ThreadProc(); @@ -171,7 +175,7 @@ public: void HandlePendingEntries(); void Process(); void DoClear(); - ProfileProcId* Get(const StringImpl& str); + ProfileProcId* Get(const StringImpl& str, bool* outIsNew = NULL); public: DbgProfiler(WinDebugger* debugger); diff --git a/IDEHelper/Tests/Test0.txt b/IDEHelper/Tests/Test0.txt new file mode 100644 index 00000000..5f0767fa --- /dev/null +++ b/IDEHelper/Tests/Test0.txt @@ -0,0 +1,2 @@ +Test +0 \ No newline at end of file diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 453e39c7..117e3424 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -183,7 +183,7 @@ namespace Tests mStr.AppendF($"{name} {val}\n"); } } - + interface ISerializable { void Serialize(SerializationContext ctx); @@ -229,6 +229,43 @@ namespace Tests GC.Mark!((*ptr)); } } + + [CheckEnum] + enum EnumA + { + case A(int64 aa); + case B(float bb); + } + + [AttributeUsage(.All)] + public struct CheckEnumAttribute : Attribute, IComptimeTypeApply + { + public void ApplyToType(Type type) + { + int fieldIdx = 0; + for (var field in type.GetFields()) + { + switch (fieldIdx) + { + case 0: + Test.Assert(field.Name == "$payload"); + Test.Assert(field.MemberOffset == 0); + Test.Assert(field.FieldType == typeof(int64)); + case 1: + Test.Assert(field.Name == "$discriminator"); + Test.Assert(field.MemberOffset == 8); + Test.Assert(field.FieldType == typeof(int8)); + } + fieldIdx++; + } + Test.Assert(fieldIdx == 4); + } + } + + const String cTest0 = Compiler.ReadText("Test0.txt"); + const String cTest1 = new String('A', 12); + const uint8[?] cTest0Binary = Compiler.ReadBinary("Test0.txt"); + [Test] public static void TestBasics() { @@ -269,6 +306,11 @@ namespace Tests SerializationContext serCtx = scope .(); iSer.Serialize(serCtx); Test.Assert(serCtx.mStr == "x 10\ny 2\n"); + + Test.Assert(cTest0 == "Test\n0"); + Test.Assert(cTest1 == "AAAAAAAAAAAA"); + Test.Assert((Object)cTest1 == (Object)"AAAAAAAAAAAA"); + Test.Assert((cTest0Binary[0] == (.)'T') && ((cTest0Binary.Count == 6) || (cTest0Binary.Count == 7))); } } } diff --git a/IDEHelper/Tests/src/FuncRefs.bf b/IDEHelper/Tests/src/FuncRefs.bf index f63d4eaa..76dedf7c 100644 --- a/IDEHelper/Tests/src/FuncRefs.bf +++ b/IDEHelper/Tests/src/FuncRefs.bf @@ -57,6 +57,65 @@ namespace Tests return dlg(val[0]); } + static void TestWrap(T del, bool b = false) where T : delegate void() + { + Action ac = scope () => { + del(); + }; + ac(); + } + + struct Vector2 : this(float x, float y) + { + } + + class Invoker + { + public int mA = 111; + + public void Invoke() + { + mA += 222; + } + } + + class TestA + { + Vector2 mVec = .(11, 22); + Event mEvt ~ _.Dispose(); + Action mAct; + + public Vector2 Vec + { + set + { + DoIt(() => + { + Test.Assert(mVec.x == 11); + Test.Assert(mVec.y == 22); + Test.Assert(value.x == 33); + Test.Assert(value.y == 44); + }); + Invoker invoker = scope .(); + mEvt.Add(new => invoker); + DoIt(=> mEvt); + Test.Assert(invoker.mA == 333); + DoIt(=> invoker); + Test.Assert(invoker.mA == 555); + mAct = scope => invoker; + mAct(); + Test.Assert(invoker.mA == 777); + DoIt(=> mAct); + Test.Assert(invoker.mA == 999); + } + } + + public void DoIt(TDlg dlg) where TDlg : delegate void() + { + dlg(); + } + } + [Test] public static void TestBasics() { @@ -78,6 +137,13 @@ namespace Tests List fList = scope .() { 1.2f, 2.3f }; Test.Assert(DoOnListA(fList, (val) => val + 100) == 101.2f); Test.Assert(DoOnListB((val) => val + 200, fList) == 201.2f); + + int a = 222; + TestWrap(() => { a += 100; }); + Test.Assert(a == 322); + + TestA ta = scope .(); + ta.Vec = .(33, 44); } struct MethodRefHolder where T : delegate int(int num) diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 01d420b6..a5999428 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -23,6 +23,16 @@ namespace Tests { class Generics { + struct StructA : IDisposable + { + int mA = 123; + + public void Dispose() + { + + } + } + class ClassA : IDisposable, LibA.IVal { int LibA.IVal.Val @@ -172,7 +182,7 @@ namespace Tests delete val; } - public static void Alloc2() where T : new, delete, IDisposable, struct + public static void Alloc2() where T : new, IDisposable, struct { alloctype(T) val = new T(); T* val2 = val; @@ -180,6 +190,14 @@ namespace Tests delete val; } + public static void Alloc3() where T : new, IDisposable, struct* + { + T val2 = default; + if (val2 != null) + val2.Dispose(); + delete val2; + } + public class ClassE { public static Self Instance = new ClassE() ~ delete _; @@ -311,6 +329,9 @@ namespace Tests [Test] public static void TestBasics() { + Alloc2(); + Alloc3(); + MethodD(scope => MethodC); List list = scope .();