1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Merge branch 'master' into FuzzyAutoComplete

This commit is contained in:
Brian Fiete 2021-12-28 17:07:19 +01:00 committed by GitHub
commit 62c3998521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 2485 additions and 598 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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:

View file

@ -10,6 +10,7 @@ namespace Beefy.widgets
public interface IMenu
{
void SetDisabled(bool enable);
void SetCheckState(int32 checkState);
}
public interface IMenuContainer

View file

@ -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)

View file

@ -616,5 +616,10 @@ namespace Beefy.widgets
{
mDisabled = disabled;
}
public void SetCheckState(int32 checkState)
{
}
}
}

View file

@ -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
{

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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<uint8> ReadBinary(StringView path)
{
List<uint8> data = scope .();
File.ReadAll(path, data);
return data;
}
[Comptime]
public static String ReadText(StringView path)
{
String data = scope .();
File.ReadAllText(path, data);
return data;
}
}
}

View file

@ -106,5 +106,24 @@ namespace System.Diagnostics
if (gIsDebuggerPresent)
Break();
}
public static void WriteMemory(Span<uint8> 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>(T result)
{
#unwarn
WriteMemory(.((.)&result, sizeof(T)));
}
}
}

View file

@ -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;
}
}

View file

@ -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>(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<TEnum> GetEnumerator<TEnum>()
where TEnum : enum
{
return .();
}
public static EnumValuesEnumerator<TEnum> GetValues<TEnum>()
where TEnum : enum
{
return .();
}
public static EnumNamesEnumerator<TEnum> GetNames<TEnum>()
where TEnum : enum
{
return .();
}
private struct EnumFieldsEnumerator<TEnum>
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<FieldInfo> GetNext() mut
{
if (!MoveNext())
return .Err;
return Current;
}
}
public struct EnumEnumerator<TEnum> : EnumFieldsEnumerator<TEnum>, 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<TEnum> : EnumFieldsEnumerator<TEnum>, IEnumerator<TEnum>
where TEnum : enum
{
public new TEnum Current
{
get
{
return (.)base.Current.[Friend]mFieldData.[Friend]mData;
}
}
public new Result<TEnum> GetNext() mut
{
if (!MoveNext())
return .Err;
return Current;
}
}
public struct EnumNamesEnumerator<TEnum> : EnumFieldsEnumerator<TEnum>, IEnumerator<StringView>
where TEnum : enum
{
public new StringView Current
{
get
{
return (.)base.Current.[Friend]mFieldData.[Friend]mName;
}
}
public new Result<StringView> GetNext() mut
{
if (!MoveNext())
return .Err;
return Current;
}
}
}
}

View file

@ -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

View file

@ -118,6 +118,9 @@ namespace System
public this()
{
if (Compiler.IsComptime)
return;
#if BF_PLATFORM_WINDOWS
bool isWinSrv()
{

View file

@ -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;
}

View file

@ -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<String> enumerable)
{

View file

@ -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

View file

@ -2,7 +2,7 @@ using System.Diagnostics;
namespace System
{
struct Variant
struct Variant : IDisposable
{
enum ObjectType
{
@ -472,4 +472,4 @@ namespace System
return variant;
}
}
}
}

View file

@ -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
{

View file

@ -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();

View file

@ -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);

View file

@ -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)
{

View file

@ -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<KeyState, IDECommandBase> mMap = new .() ~ delete _;
public List<IDECommandBase> mFailValues ~ delete _;
public List<IDECommandBase> 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);

View file

@ -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);
}
}
}

View file

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

View file

@ -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;
}

View file

@ -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<String> 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

View file

@ -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<FileRecoveryKind>("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;

View file

@ -1165,6 +1165,7 @@ namespace IDE.ui
}
}
public Stopwatch mStopwatch ~ delete _;
public EditWidget mTargetEditWidget;
public Event<Action> mOnAutoCompleteInserted ~ _.Dispose();
public Event<Action> mOnClosed ~ _.Dispose();

View file

@ -136,17 +136,15 @@ namespace IDE.ui
ClearAndDeleteItems(mResolveErrors);
mResolveErrors.Capacity = mResolveErrors.Count;
}
var bfl = scope:: List<BfPassInstance.BfError>();
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<BfPassInstance.BfError>();
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();

View file

@ -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();

View file

@ -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<ThreadEntry> 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);
}
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
});

View file

@ -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")
// ;

View file

@ -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 ################

View file

@ -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<TestMethod>& 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<TestMethod>& 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<TestMethod>& 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<BfProject*> 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();

View file

@ -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;

View file

@ -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<BfTypeInstance*> defStateChangedQueue;
Array<BfTypeInstance*> defEmitParentCheckQueue;
Dictionary<String, uint64> 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);

View file

@ -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);

View file

@ -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;

View file

@ -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<int, int>& 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<int, int>& 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<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration))
if (methodDeclaration->mReadOnlySpecifier != NULL)
Fail("Readonly specifier is only valid on 'ref' return types", methodDeclaration->mReadOnlySpecifier);
}
}
else
{

View file

@ -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<BfTypeInstance*> foundAttributes);
void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> 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<BfTypeReference*>* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);

View file

@ -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<BfTypeInstance*> foundAttributes)
void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> 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<BfTypeInstance*> 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<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeAlias);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
SetAndRestoreValue<BfMethodState*> 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<BfTypeState::ResolveKind> 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<BfNamedTypeReference>())
{
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<BfDelegateTypeRef>(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 += "(";

View file

@ -3800,13 +3800,14 @@ BF_EXPORT bool BF_CALLTYPE BfParser_Reduce(BfParser* bfParser, BfPassInstance* b
}
static Array<int> 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;

View file

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

View file

@ -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<BfTokenNode>(checkNode))
{
if (checkToken->mToken == BfToken_LBracket)
{
while (true)
{
mVisitorPos.mReadPos++;
checkNode = mVisitorPos.GetCurrent();
if (checkNode == NULL)
{
failed = true;
break;
}
if (BfNodeIsA<BfBlock>(checkNode))
{
failed = true;
break;
}
if (checkToken = BfNodeDynCast<BfTokenNode>(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<BfTokenNode>(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);

View file

@ -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;

View file

@ -452,6 +452,7 @@ public:
Array<BfType*> 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<int, BfCeTypeEmitEntry> mOnCompileMap;
Dictionary<int, BfCeTypeEmitEntry> mTypeIFaceMap;
Array<int> 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<BfTypeReference*, BfType*> 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);

View file

@ -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;

View file

@ -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);

View file

@ -1180,6 +1180,7 @@ public:
BfSystem* mSystem;
String mName;
String mSafeName;
String mDirectory;
Array<BfProject*> mDependencies;
BfTargetType mTargetType;
BfCodeGenOptions mCodeGenOptions;

View file

@ -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<BfMethodState*> 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<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType)
@ -7246,3 +7745,5 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
ReleaseContext(ceContext);
return result;
}

View file

@ -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<int32> mInterfaces;
Array<int32> mInterfaces;
String mEmitData;
String mExitEmitData;
bool mFailed;
@ -706,6 +781,25 @@ public:
}
};
class BfCeTypeInfo
{
public:
Dictionary<int, BfCeTypeEmitEntry> mOnCompileMap;
Dictionary<int, BfCeTypeEmitEntry> mTypeIFaceMap;
Array<int> mPendingInterfaces;
Dictionary<CeRebuildKey, CeRebuildValue> mRebuildMap;
Val128 mHash;
bool mFailed;
BfCeTypeInfo* mNext;
public:
BfCeTypeInfo()
{
mFailed = false;
mNext = NULL;
}
};
class CeContext
{
public:
@ -719,19 +813,21 @@ public:
ContiguousHeap* mHeap;
Array<CeFrame> mCallStack;
Array<uint8> mMemory;
int mStackSize;
Dictionary<int, addr_ce> mStringMap;
Dictionary<int, addr_ce> mReflectMap;
Dictionary<Val128, addr_ce> mConstDataMap;
HashSet<int> mStaticCtorExecSet;
Dictionary<String, CeStaticFieldInfo> mStaticFieldMap;
Dictionary<void*, addr_ce> mMemToCtxMap;
Dictionary<int, CeInternalData*> 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<Beefy::CeRebuildKey>
{
size_t operator()(const Beefy::CeRebuildKey& key) const
{
return BeefHash<Beefy::String>()(key.mString) ^ (size_t)key.mKind;
}
};
}

View file

@ -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<int> idleThreadSet;
@ -218,9 +230,11 @@ void DbgProfiler::ThreadProc()
iterations++;
DWORD startTick0 = timeGetTime();
idleThreadSet.Clear();
SYSTEM_PROCESS_INFORMATION* processData = NULL;
std::unique_ptr<SYSTEM_PROCESS_INFORMATION> ptrDelete(processData);
std::unique_ptr<SYSTEM_PROCESS_INFORMATION> 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(&registers);
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<ProfileProcEntry*>& 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<ProfileProcEntry*>& 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<ProfileProcEntry*>& 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<ProfileProcEntry*>& 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<ProfileProcEntry*>& 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<ProfileProcEntry*> procEntries;
@ -714,10 +756,10 @@ String DbgProfiler::GetCallTree(int threadId, bool reverse)
int idleTicks = totalSampleCount - totalActiveSampleCount;
if (idleTicks != 0)
str += StrFormat("<Idle>\t%d\t0\n-\n", idleTicks);
AddEntries(str, procEntries, 0, (int)procEntries.size(), -1, NULL);
str += "-\n";
str += "-\n";
//BF_ASSERT(childSampleCount == totalSampleCount);

View file

@ -67,6 +67,7 @@ class ProfileProcId
{
public:
String mProcName;
bool mIsIdle;
};
class ProfileProdIdEntry
@ -104,12 +105,14 @@ class ProfileThreadInfo
public:
Array<int> mProfileAddrEntries;
int mTotalSamples;
int mTotalIdleSamples;
String mName;
public:
ProfileThreadInfo()
{
mTotalSamples = 0;
mTotalIdleSamples = 0;
}
};
@ -143,6 +146,7 @@ public:
Dictionary<void*, ProfileProcId*> mProcMap; // Keyed on either DwSubprogram or DwSymbol. Multiple pointers can reference the same ProfileProcId (in the case of inlined functions, for example)
HashSet<ProfileProdIdEntry> mUniqueProcSet;
HashSet<String> 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);

View file

@ -0,0 +1,2 @@
Test
0

View file

@ -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)));
}
}
}

View file

@ -57,6 +57,65 @@ namespace Tests
return dlg(val[0]);
}
static void TestWrap<T>(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<Action> 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>(TDlg dlg) where TDlg : delegate void()
{
dlg();
}
}
[Test]
public static void TestBasics()
{
@ -78,6 +137,13 @@ namespace Tests
List<float> 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<T> where T : delegate int(int num)

View file

@ -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<T>() where T : new, delete, IDisposable, struct
public static void Alloc2<T>() 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<T>() 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<StructA>();
Alloc3<StructA*>();
MethodD(scope => MethodC);
List<Entry> list = scope .();