1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Beefy::String changes, lambda hotswap fixes

Changed some string internals related to StringViewsma
Added an "incompatible capture" error for lambdas when the captures change
This commit is contained in:
Brian Fiete 2019-09-03 11:17:13 -07:00
parent 767a3fafd9
commit 2f01cc14dd
25 changed files with 544 additions and 180 deletions

View file

@ -4,6 +4,7 @@ using Beefy.gfx;
using System.Diagnostics; using System.Diagnostics;
using System; using System;
using System.IO; using System.IO;
using System.Threading;
namespace BIStubUI namespace BIStubUI
{ {
@ -202,10 +203,13 @@ namespace BIStubUI
float mEatPct; float mEatPct;
int mCloseTicks; int mCloseTicks;
int mInstallTicks;
public bool mIsClosed; public bool mIsClosed;
bool mUninstallDone;
public bool mInstalling; public bool mInstalling;
public float mInstallPct = 0.5f; public bool mUninstalling;
public float mInstallPct;
public this() public this()
{ {
@ -256,7 +260,7 @@ namespace BIStubUI
mCancelButton.mImageHi = Images.sButtonHi; mCancelButton.mImageHi = Images.sButtonHi;
mCancelButton.mOnMouseClick.Add(new (mouseArgs) => mCancelButton.mOnMouseClick.Add(new (mouseArgs) =>
{ {
gApp.mCancelling = true; //gApp.mCancelling = true;
}); });
mCancelButton.mMouseInsets = new Insets(4, 4, 4, 4); mCancelButton.mMouseInsets = new Insets(4, 4, 4, 4);
AddWidget(mCancelButton); AddWidget(mCancelButton);
@ -289,6 +293,12 @@ namespace BIStubUI
mInstallPathBox.mInstallPath.Append(@"\BeefLang"); mInstallPathBox.mInstallPath.Append(@"\BeefLang");
} }
void Uninstall()
{
Thread.Sleep(10000);
mUninstallDone = true;
}
void StartInstall() void StartInstall()
{ {
mInstalling = true; mInstalling = true;
@ -320,13 +330,15 @@ namespace BIStubUI
if (mInstalling) if (mInstalling)
{ {
float installDiv = 1000.0f; //float installDiv = 1000.0f;
//mInstallPct = (mUpdateCnt % installDiv) / installDiv; //mInstallPct = (mUpdateCnt % installDiv) / installDiv;
//mInstallPct = 1.0f; //mInstallPct = 1.0f;
float totalWidth = 410; float totalWidth = 410;
float fillWidth = totalWidth * (mInstallPct*0.9f + 0.1f); float fillWidth = totalWidth * (mInstallPct*0.9f + 0.1f);
if (mUninstalling)
fillWidth = totalWidth * mInstallPct;
float barX = 200; float barX = 200;
float barY = 280; float barY = 280;
@ -338,15 +350,19 @@ namespace BIStubUI
Color colorLeft = 0x800288E9; Color colorLeft = 0x800288E9;
Color colorRight = 0x80FFFFFF; Color colorRight = 0x80FFFFFF;
if (gApp.mClosing)
{
colorLeft = 0x80000000;
colorRight = 0x800288E9;
}
g.FillRectGradient(barX, barY, fillWidth, barHeight, colorLeft, colorRight, colorLeft, colorRight); g.FillRectGradient(barX, barY, fillWidth, barHeight, colorLeft, colorRight, colorLeft, colorRight);
float pct = (mUpdateCnt % 60) / 60.0f; float barPct = (mInstallTicks % 60) / 60.0f;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
Images.sPBBarHilite.mPixelSnapping = .Never; Images.sPBBarHilite.mPixelSnapping = .Never;
using (g.PushColor(0x22FFFFFF)) using (g.PushColor(0x22FFFFFF))
g.Draw(Images.sPBBarHilite, barX - 16 - totalWidth + fillWidth + (i + pct) * 26, barY + 6); g.Draw(Images.sPBBarHilite, barX - 16 - totalWidth + fillWidth + (i + barPct) * 26, barY + 6);
} }
g.DrawButton(Images.sPBBarEmpty, barX + fillWidth - 30, barY + 5, totalWidth - fillWidth + 40); g.DrawButton(Images.sPBBarEmpty, barX + fillWidth - 30, barY + 5, totalWidth - fillWidth + 40);
@ -395,6 +411,15 @@ namespace BIStubUI
base.DrawAll(g); base.DrawAll(g);
} }
public bool IsDecompressing
{
get
{
//return gApp.
return false;
}
}
public override void Update() public override void Update()
{ {
base.Update(); base.Update();
@ -403,6 +428,34 @@ namespace BIStubUI
if (gApp.mClosing) if (gApp.mClosing)
{ {
mCancelButton.mDisabled = true;
mCancelButton.mMouseVisible = false;
if ((mInstalling) && (!mUninstallDone))
{
if ((!IsDecompressing) && (!mUninstalling))
{
mUninstalling = true;
ThreadPool.QueueUserWorkItem(new => Uninstall);
}
mInstallTicks--;
if (mInstallTicks < 0)
mInstallTicks = 0x3FFFFFFF;
}
if (mInstallPct > 0)
{
mInstallPct = (mInstallPct * 0.98f) - 0.003f;
if (!mUninstallDone)
mInstallPct = Math.Max(mInstallPct, 0.1f);
return;
}
if ((mInstalling) && (!mUninstallDone))
{
return;
}
if (mCloseTicks == 0) if (mCloseTicks == 0)
{ {
gApp.mSoundManager.PlaySound(Sounds.sAbort); gApp.mSoundManager.PlaySound(Sounds.sAbort);
@ -427,6 +480,9 @@ namespace BIStubUI
return; return;
} }
if (mInstalling)
mInstallTicks++;
if (mUpdateCnt == 1) if (mUpdateCnt == 1)
gApp.mSoundManager.PlaySound(Sounds.sBoing); gApp.mSoundManager.PlaySound(Sounds.sBoing);

View file

@ -483,6 +483,15 @@ public:
return true; return true;
} }
// template <typename TAltKey>
// bool TryAddWith(const TAltKey& key, TKey** keyPtr, TValue** valuePtr)
// {
// if (!Insert(key, false, keyPtr, valuePtr))
// return false;
// new (*valuePtr) TValue();
// return true;
// }
// Returns uninitialized valuePtr - must use placement new // Returns uninitialized valuePtr - must use placement new
bool TryAddRaw(const TKey& key, TKey** keyPtr, TValue** valuePtr) bool TryAddRaw(const TKey& key, TKey** keyPtr, TValue** valuePtr)
{ {

View file

@ -157,7 +157,7 @@ public:
String mName; String mName;
public: public:
DebugTimeGuard(int maxTicks, const StringImpl& name = "DebugTimeGuard") DebugTimeGuard(int maxTicks, const StringImpl& name = StringImpl::MakeRef("DebugTimeGuard"))
{ {
mName = name; mName = name;
mMaxTicks = maxTicks; mMaxTicks = maxTicks;

View file

@ -129,6 +129,16 @@ String Beefy::operator+(const StringImpl& lhs, const StringView& rhs)
return str; return str;
} }
String Beefy::operator+(const StringImpl& lhs, const char* rhs)
{
String str;
int rhsLen = (int)strlen(rhs);
str.Reserve(lhs.mLength + rhsLen + 1);
str.Append(lhs);
str.Append(rhs, rhsLen);
return str;
}
String Beefy::operator+(const StringImpl& lhs, char rhs) String Beefy::operator+(const StringImpl& lhs, char rhs)
{ {
String str; String str;
@ -138,6 +148,26 @@ String Beefy::operator+(const StringImpl& lhs, char rhs)
return str; return str;
} }
String Beefy::operator+(const char* lhs, const StringImpl& rhs)
{
String str;
int lhsLen = (int)strlen(lhs);
str.Reserve(rhs.mLength + lhsLen + 1);
str.Append(lhs, lhsLen);
str.Append(rhs);
return str;
}
String Beefy::operator+(const char* lhs, const StringView& rhs)
{
String str;
int lhsLen = (int)strlen(lhs);
str.Reserve(rhs.mLength + lhsLen + 1);
str.Append(lhs, lhsLen);
str.Append(rhs);
return str;
}
bool Beefy::operator==(const char* lhs, const StringImpl& rhs) bool Beefy::operator==(const char* lhs, const StringImpl& rhs)
{ {
return rhs == lhs; return rhs == lhs;
@ -363,6 +393,11 @@ intptr StringImpl::CompareOrdinalHelper(const StringImpl & strA, intptr indexA,
return CompareOrdinalHelper(strA.GetPtr() + indexA, lengthA, strB.GetPtr() + indexB, lengthB); return CompareOrdinalHelper(strA.GetPtr() + indexA, lengthA, strB.GetPtr() + indexB, lengthB);
} }
void StringImpl::Append(const char* appendPtr)
{
Append(appendPtr, (int)strlen(appendPtr));
}
void StringImpl::Append(const char* appendPtr, intptr length) void StringImpl::Append(const char* appendPtr, intptr length)
{ {
intptr newCurrentIndex = mLength + length; intptr newCurrentIndex = mLength + length;
@ -538,7 +573,7 @@ intptr StringImpl::Compare(const StringImpl & strA, intptr indexA, const StringI
return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB); return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
} }
void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl & replace) void StringImpl::ReplaceLargerHelper(const StringView& find, const StringView& replace)
{ {
Array<int> replaceEntries; Array<int> replaceEntries;
@ -546,7 +581,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl &
for (int startIdx = 0; startIdx < mLength - find.mLength; startIdx++) for (int startIdx = 0; startIdx < mLength - find.mLength; startIdx++)
{ {
if (EqualsHelper(GetPtr() + startIdx, find.GetPtr(), find.mLength)) if (EqualsHelper(GetPtr() + startIdx, find.mPtr, find.mLength))
{ {
replaceEntries.Add(startIdx); replaceEntries.Add(startIdx);
startIdx += find.mLength - 1; startIdx += find.mLength - 1;
@ -561,7 +596,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl &
if (needSize > GetAllocSize()) if (needSize > GetAllocSize())
Realloc((int_strsize)needSize); Realloc((int_strsize)needSize);
auto replacePtr = replace.GetPtr(); auto replacePtr = replace.mPtr;
auto ptr = GetMutablePtr(); auto ptr = GetMutablePtr();
intptr lastDestStartIdx = destLength; intptr lastDestStartIdx = destLength;
@ -585,7 +620,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl &
mLength = (int_strsize)destLength; mLength = (int_strsize)destLength;
} }
void StringImpl::Replace(const StringImpl & find, const StringImpl & replace) void StringImpl::Replace(const StringView& find, const StringView & replace)
{ {
if (replace.mLength > find.mLength) if (replace.mLength > find.mLength)
{ {
@ -594,8 +629,8 @@ void StringImpl::Replace(const StringImpl & find, const StringImpl & replace)
} }
auto ptr = GetMutablePtr(); auto ptr = GetMutablePtr();
auto findPtr = find.GetPtr(); auto findPtr = find.mPtr;
auto replacePtr = replace.GetPtr(); auto replacePtr = replace.mPtr;
int_strsize inIdx = 0; int_strsize inIdx = 0;
int_strsize outIdx = 0; int_strsize outIdx = 0;
@ -693,7 +728,7 @@ bool StringImpl::HasMultibyteChars()
return false; return false;
} }
intptr StringImpl::IndexOf(const StringImpl& subStr, bool ignoreCase) const intptr StringImpl::IndexOf(const StringView& subStr, bool ignoreCase) const
{ {
for (intptr ofs = 0; ofs <= mLength - subStr.mLength; ofs++) for (intptr ofs = 0; ofs <= mLength - subStr.mLength; ofs++)
{ {
@ -704,15 +739,15 @@ intptr StringImpl::IndexOf(const StringImpl& subStr, bool ignoreCase) const
return -1; return -1;
} }
intptr StringImpl::IndexOf(const StringImpl& subStr, int32 startIdx) const intptr StringImpl::IndexOf(const StringView& subStr, int32 startIdx) const
{ {
return IndexOf(subStr, (int64)startIdx); return IndexOf(subStr, (int64)startIdx);
} }
intptr StringImpl::IndexOf(const StringImpl& subStr, int64 startIdx) const intptr StringImpl::IndexOf(const StringView& subStr, int64 startIdx) const
{ {
const char* ptr = GetPtr(); const char* ptr = GetPtr();
const char* subStrPtr = subStr.GetPtr(); const char* subStrPtr = subStr.mPtr;
for (intptr ofs = (intptr)startIdx; ofs <= mLength - subStr.mLength; ofs++) for (intptr ofs = (intptr)startIdx; ofs <= mLength - subStr.mLength; ofs++)
{ {
if (strncmp(ptr + ofs, subStrPtr, subStr.mLength) == 0) if (strncmp(ptr + ofs, subStrPtr, subStr.mLength) == 0)

View file

@ -33,6 +33,12 @@ public:
StringView(const StringImpl& str, int offset); StringView(const StringImpl& str, int offset);
StringView(const StringImpl& str, int offset, int length); StringView(const StringImpl& str, int offset, int length);
StringView(const char* ptr)
{
this->mPtr = ptr;
this->mLength = (int)strlen(ptr);
}
StringView(const char* ptr, int length) StringView(const char* ptr, int length)
{ {
this->mPtr = ptr; this->mPtr = ptr;
@ -54,6 +60,13 @@ public:
return *this; return *this;
} }
StringView& operator=(const char* str)
{
this->mPtr = str;
this->mLength = (int)strlen(str);
return *this;
}
bool operator==(const StringImpl& strB) const; bool operator==(const StringImpl& strB) const;
bool operator!=(const StringImpl& strB) const; bool operator!=(const StringImpl& strB) const;
@ -339,6 +352,26 @@ protected:
public: public:
static StringImpl MakeRef(const char* charPtr)
{
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)strlen(charPtr);
str.mAllocSizeAndFlags = str.mLength | StrPtrFlag;
return str;
}
static StringImpl MakeRef(const StringView& strView)
{
StringImpl str;
// This is just a ref - called when we pass a literal to a method (for example)
str.mPtr = (char*)strView.mPtr;
str.mLength = (int_strsize)strView.mLength;
str.mAllocSizeAndFlags = str.mLength | StrPtrFlag;
return str;
}
StringImpl(const char* charPtr) StringImpl(const char* charPtr)
{ {
// This is just a ref - called when we pass a literal to a method (for example) // This is just a ref - called when we pass a literal to a method (for example)
@ -617,6 +650,7 @@ public:
static String CreateReference(const StringView& strView); static String CreateReference(const StringView& strView);
void Reserve(intptr newSize); void Reserve(intptr newSize);
void Append(const char* appendPtr);
void Append(const char* appendPtr, intptr length); void Append(const char* appendPtr, intptr length);
void Append(const StringView& str); void Append(const StringView& str);
void Append(const StringImpl& str); void Append(const StringImpl& str);
@ -672,22 +706,22 @@ public:
return EqualsHelper(a.GetPtr(), b.GetPtr(), a.mLength); return EqualsHelper(a.GetPtr(), b.GetPtr(), a.mLength);
} }
bool StartsWith(const StringImpl& b, CompareKind comparisonType = CompareKind_Ordinal) const bool StartsWith(const StringView& b, CompareKind comparisonType = CompareKind_Ordinal) const
{ {
if (this->mLength < b.mLength) if (this->mLength < b.mLength)
return false; return false;
if (comparisonType == CompareKind_OrdinalIgnoreCase) if (comparisonType == CompareKind_OrdinalIgnoreCase)
return EqualsIgnoreCaseHelper(this->GetPtr(), b.GetPtr(), b.mLength); return EqualsIgnoreCaseHelper(this->GetPtr(), b.mPtr, b.mLength);
return EqualsHelper(this->GetPtr(), b.GetPtr(), b.mLength); return EqualsHelper(this->GetPtr(), b.mPtr, b.mLength);
} }
bool EndsWith(const StringImpl& b, CompareKind comparisonType = CompareKind_Ordinal) const bool EndsWith(const StringView& b, CompareKind comparisonType = CompareKind_Ordinal) const
{ {
if (this->mLength < b.mLength) if (this->mLength < b.mLength)
return false; return false;
if (comparisonType == CompareKind_OrdinalIgnoreCase) if (comparisonType == CompareKind_OrdinalIgnoreCase)
return EqualsIgnoreCaseHelper(this->GetPtr() + this->mLength - b.mLength, b.GetPtr(), b.mLength); return EqualsIgnoreCaseHelper(this->GetPtr() + this->mLength - b.mLength, b.mPtr, b.mLength);
return EqualsHelper(this->GetPtr() + this->mLength - b.mLength, b.GetPtr(), b.mLength); return EqualsHelper(this->GetPtr() + this->mLength - b.mLength, b.mPtr, b.mLength);
} }
bool StartsWith(char c) const bool StartsWith(char c) const
@ -704,8 +738,8 @@ public:
return GetPtr()[this->mLength - 1] == c; return GetPtr()[this->mLength - 1] == c;
} }
void ReplaceLargerHelper(const StringImpl& find, const StringImpl& replace); void ReplaceLargerHelper(const StringView& find, const StringView& replace);
void Replace(const StringImpl& find, const StringImpl& replace); void Replace(const StringView& find, const StringView& replace);
void TrimEnd(); void TrimEnd();
void TrimStart(); void TrimStart();
void Trim(); void Trim();
@ -721,9 +755,9 @@ public:
} }
bool HasMultibyteChars(); bool HasMultibyteChars();
intptr IndexOf(const StringImpl& subStr, bool ignoreCase = false) const; intptr IndexOf(const StringView& subStr, bool ignoreCase = false) const;
intptr IndexOf(const StringImpl& subStr, int32 startIdx) const; intptr IndexOf(const StringView& subStr, int32 startIdx) const;
intptr IndexOf(const StringImpl& subStr, int64 startIdx) const; intptr IndexOf(const StringView& subStr, int64 startIdx) const;
intptr IndexOf(char c, intptr startIdx = 0) const; intptr IndexOf(char c, intptr startIdx = 0) const;
intptr LastIndexOf(char c) const; intptr LastIndexOf(char c) const;
intptr LastIndexOf(char c, intptr startCheck) const; intptr LastIndexOf(char c, intptr startCheck) const;
@ -732,8 +766,8 @@ public:
{ {
return IndexOf(c) != -1; return IndexOf(c) != -1;
} }
bool Contains(const StringImpl& str) const bool Contains(const StringView& str) const
{ {
return IndexOf(str) != -1; return IndexOf(str) != -1;
} }
@ -909,7 +943,7 @@ public: \
using StringImpl::StringImpl; \ using StringImpl::StringImpl; \
using StringImpl::operator=; \ using StringImpl::operator=; \
StringT() { mPtr = NULL; mLength = 0; mAllocSizeAndFlags = 0; } \ StringT() { mPtr = NULL; mLength = 0; mAllocSizeAndFlags = 0; } \
StringT(const char* str) { Init(str, (int_strsize)strlen(str)); } \ explicit StringT(const char* str) { Init(str, (int_strsize)strlen(str)); } \
StringT(const std::string& str) { Init(str.c_str(), (int_strsize)str.length()); } \ StringT(const std::string& str) { Init(str.c_str(), (int_strsize)str.length()); } \
StringT(const StringImpl& str) : StringImpl(str) {} \ StringT(const StringImpl& str) : StringImpl(str) {} \
StringT(StringImpl&& str) : StringImpl(std::move(str)) {} \ StringT(StringImpl&& str) : StringImpl(std::move(str)) {} \
@ -927,7 +961,11 @@ BF_SPECIALIZE_STR(6)
String operator+(const StringImpl& lhs, const StringImpl& rhs); String operator+(const StringImpl& lhs, const StringImpl& rhs);
String operator+(const StringImpl& lhs, const StringView& rhs); String operator+(const StringImpl& lhs, const StringView& rhs);
String operator+(const StringImpl& lhs, const char* rhs);
String operator+(const StringImpl& lhs, char rhs); String operator+(const StringImpl& lhs, char rhs);
String operator+(const char* lhs, const StringImpl& rhs);
String operator+(const char* lhs, const StringView& rhs);
bool operator==(const char* lhs, const StringImpl& rhs); bool operator==(const char* lhs, const StringImpl& rhs);
bool operator!=(const char* lhs, const StringImpl& rhs); bool operator!=(const char* lhs, const StringImpl& rhs);
// bool operator==(const StringView& lhs, const StringImpl& rhs); // bool operator==(const StringView& lhs, const StringImpl& rhs);

View file

@ -27,7 +27,7 @@ TargetDirectory = "$(WorkspaceDir)/dist"
TargetName = "BeefIDE_d" TargetName = "BeefIDE_d"
OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib"
CLibType = "Dynamic" CLibType = "Dynamic"
DebugCommandArguments = "-proddir=C:\\Beef\\IDE\\Tests\\Test1 -platform=Win32 -test=scripts\\Break.txt -testNoExit" DebugCommandArguments = "-proddir=C:\\Beef\\IDE\\Tests\\Test1 -test=scripts\\HotSwap_Lambdas01.txt -testNoExit"
DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest" DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest"
EnvironmentVars = ["_NO_DEBUG_HEAP=1"] EnvironmentVars = ["_NO_DEBUG_HEAP=1"]

View file

@ -0,0 +1,28 @@
# This tests modifying anonymous lambdas, including changing captured data (both legally and illegally)
ShowFile("src/HotSwap_Lambdas01.bf")
GotoText("//Test_Start")
ToggleBreakpoint()
RunWithCompiling()
StepOver()
StepOver()
StepOver()
StepOver()
AssertEvalEquals("val0", "200")
AssertEvalEquals("val1", "423")
AssertEvalEquals("val2", "757")
ToggleCommentAt("Dlg0_0")
ToggleCommentAt("Dlg1_0")
ToggleCommentAt("Dlg2_0")
Compile()
SetExpectError("incompatible captures")
StepOver()
ExpectError()
StepOut()
StepOver()
StepOver()
AssertEvalEquals("val0", "200")
AssertEvalEquals("val1", "300")
AssertEvalEquals("val2", "523")

View file

@ -0,0 +1,62 @@
#pragma warning disable 168
namespace IDETest
{
class HotSwap_Lambdas01
{
class ClassA
{
public delegate int() mDlg0 ~ delete _;
public delegate int() mDlg1 ~ delete _;
public delegate int() mDlg2 ~ delete _;
int mA = 123;
public this()
{
int val = 234;
mDlg0 = new () =>
{
int ret = 200;
/*Dlg0_0
ret += mA;
*/
return ret;
};
mDlg1 = new () =>
{
int ret = 300;
//*Dlg1_0
ret += mA;
/*@*/
return ret;
};
mDlg2 = new () =>
{
int ret = 400;
//*Dlg2_0
ret += val;
/*@*/
ret += mA;
return ret;
};
}
}
public static void Test()
{
//Test_Start
ClassA ca = scope .();
int val0 = ca.mDlg0();
int val1 = ca.mDlg1();
int val2 = ca.mDlg2();
val0 = ca.mDlg0();
val1 = ca.mDlg1();
val2 = ca.mDlg2();
}
}
}

View file

@ -14,6 +14,7 @@ namespace IDETest
HotSwap_Data.Test(); HotSwap_Data.Test();
HotSwap_GetUnusued.Test(); HotSwap_GetUnusued.Test();
HotSwap_Interfaces2.Test(); HotSwap_Interfaces2.Test();
HotSwap_Lambdas01.Test();
HotSwap_LocateSym01.Test(); HotSwap_LocateSym01.Test();
HotSwap_Reflection.Test(); HotSwap_Reflection.Test();
HotSwap_TLS.Test(); HotSwap_TLS.Test();

View file

@ -10,7 +10,6 @@ IntermediateType = "ObjectAndIRCode"
ConfigSelections = {mintest2 = {Enabled = false}} ConfigSelections = {mintest2 = {Enabled = false}}
[Configs.Debug.Win64] [Configs.Debug.Win64]
BfOptimizationLevel = "O0"
IntermediateType = "ObjectAndIRCode" IntermediateType = "ObjectAndIRCode"
COptimizationLevel = "Og" COptimizationLevel = "Og"

View file

@ -87,85 +87,37 @@ struct TestStruct
public int mB; public int mB;
} }
class Bloozer
{
int mA;
}
class Blurg class Blurg
{ {
[Export, CLink, StdCall] delegate void() mFuncA;
public static void Poof() delegate void() mFuncB;
{
PrintF("Poofs!\n");
}
[Export, CLink, StdCall]
public static void Poof2()
{
PrintF("Poofs2!\n");
}
static void Test0()
{
Snorf sn = scope .();
int a = 124;
}
public void DoRecurse(int depth, ref int val)
{
Thread.Sleep(1);
++val;
if (val < 5)
{
DoRecurse(depth + 1, ref val);
}
}
public static void VoidCall()
{
}
public static int GetInt()
{
float f = 10.0f;
//f = f % 3.0f;
return 123;
}
public static void Hey() public static void Hey()
{ {
float f = 1.2f; int a = 123;
//f = f % 2.3f; Blurg blurg = scope .();
blurg.mFuncA = new () =>
{
PrintF("YoA!\n");
PrintF("A %d!\n", a);
PrintF("Blurg: %p\n", blurg);
};
TestStruct ts = .(); blurg.mFuncB = new () =>
//int val = ts..mA; {
ts.mA = 123; PrintF("YoB!\n");
};
GetInt(); while (true)
GetInt(); {
blurg.mFuncA();
VoidCall(); blurg.mFuncB();
int val0 = GetInt(); }
Blurg bl = scope .();
int val = 0;
bl.DoRecurse(0, ref val);
Test0();
Test0();
Test0();
Test0();
Result<void*> voidPtrResult = default;
//void* val = voidPtrResult;
//Result<TestStruct> ts = .Ok(.());
//let val = ts.Get();
//Snorf.Bloog bl = .();
//Poof();
} }
} }

View file

@ -3051,7 +3051,7 @@ namespace IDE
if (mRunningTestScript) if (mRunningTestScript)
{ {
if ((mScriptManager.mExpectingError != null) && (text.Contains(mScriptManager.mExpectingError))) if (mScriptManager.IsErrorExpected(text))
{ {
DeleteAndNullify!(mScriptManager.mExpectingError); DeleteAndNullify!(mScriptManager.mExpectingError);
OutputLine("Received expected error: {0}", text); OutputLine("Received expected error: {0}", text);
@ -10479,7 +10479,7 @@ namespace IDE
} }
else if (cmd == "error") else if (cmd == "error")
{ {
if ((mRunningTestScript) && (!IsCrashDump)) if ((mRunningTestScript) && (!IsCrashDump) && (!mScriptManager.IsErrorExpected(param)))
mScriptManager.Fail(param); mScriptManager.Fail(param);
bool isFirstMsg = true; bool isFirstMsg = true;
@ -10553,7 +10553,6 @@ namespace IDE
if (isFirstMsg) if (isFirstMsg)
{ {
OutputLineSmart(scope String("ERROR: ", errorMsg)); OutputLineSmart(scope String("ERROR: ", errorMsg));
Fail(errorMsg);
isFirstMsg = false; isFirstMsg = false;
} }
else else

View file

@ -177,6 +177,11 @@ namespace IDE
//gApp.mRunningTestScript = false; //gApp.mRunningTestScript = false;
} }
public bool IsErrorExpected(StringView err)
{
return (mExpectingError != null) && (err.Contains(mExpectingError));
}
public void Fail(StringView fmt, params Object[] args) public void Fail(StringView fmt, params Object[] args)
{ {
Fail(scope String()..AppendF(fmt, params args)); Fail(scope String()..AppendF(fmt, params args));

View file

@ -405,7 +405,7 @@ namespace std
{ {
size_t operator()(const NS_BF_DBG::CvModuleInfoNameEntry& val) const size_t operator()(const NS_BF_DBG::CvModuleInfoNameEntry& val) const
{ {
return NS_BF_DBG::CvModuleInfoNameEntry::GetHashCode(val.mModuleInfo->mModuleName); return NS_BF_DBG::CvModuleInfoNameEntry::GetHashCode(Beefy::StringImpl::MakeRef(val.mModuleInfo->mModuleName));
} }
}; };
} }

View file

@ -9553,7 +9553,9 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
mModule->mBfIRBuilder->PopulateType(useTypeInstance); mModule->mBfIRBuilder->PopulateType(useTypeInstance);
mModule->PopulateType(useTypeInstance); mModule->PopulateType(useTypeInstance);
methodDef->mIsStatic = closureTypeInst == NULL; // If we are allowing hot swapping, we need to always mangle the name to non-static because if we add a capture
// later then we need to have the mangled names match
methodDef->mIsStatic = (closureTypeInst == NULL) && (!mModule->mCompiler->mOptions.mAllowHotSwapping);
SizedArray<BfIRType, 3> newTypes; SizedArray<BfIRType, 3> newTypes;
SizedArray<BfIRType, 8> origParamTypes; SizedArray<BfIRType, 8> origParamTypes;
@ -9598,12 +9600,12 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
methodDef->mName.RemoveToEnd(prevSepPos); methodDef->mName.RemoveToEnd(prevSepPos);
} }
if (closureTypeInst != NULL) // if (closureTypeInst != NULL)
{ // {
StringT<128> typeInstName; // StringT<128> typeInstName;
BfMangler::Mangle(typeInstName,mModule->mCompiler->GetMangleKind(), closureTypeInst); // BfMangler::Mangle(typeInstName,mModule->mCompiler->GetMangleKind(), closureTypeInst);
closureHashCtx.MixinStr(typeInstName); // closureHashCtx.MixinStr(typeInstName);
} // }
auto checkMethodState = mModule->mCurMethodState; auto checkMethodState = mModule->mCurMethodState;
while (checkMethodState != NULL) while (checkMethodState != NULL)

View file

@ -778,11 +778,7 @@ BfModule* gLastCreatedModule = NULL;
BfModule::BfModule(BfContext* context, const StringImpl& moduleName) BfModule::BfModule(BfContext* context, const StringImpl& moduleName)
{ {
BfLogSys(context->mSystem, "BfModule::BFModule %p %s\n", this, moduleName.c_str()); BfLogSys(context->mSystem, "BfModule::BFModule %p %s\n", this, moduleName.c_str());
if (moduleName.Contains("_Comparison_"))
{
NOP;
}
gLastCreatedModule = this; gLastCreatedModule = this;
mContext = context; mContext = context;
@ -14930,7 +14926,10 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx)
mCurMethodState->mClosureState = &closureState; mCurMethodState->mClosureState = &closureState;
//closureState.mConstLocals = deferredLocalMethod->mConstLocals; //closureState.mConstLocals = deferredLocalMethod->mConstLocals;
closureState.mReturnType = lambdaInstance->mMethodInstance->mReturnType; closureState.mReturnType = lambdaInstance->mMethodInstance->mReturnType;
closureState.mClosureType = lambdaInstance->mClosureTypeInstance; if (lambdaInstance->mClosureTypeInstance != NULL)
closureState.mClosureType = lambdaInstance->mClosureTypeInstance;
else
closureState.mClosureType = lambdaInstance->mDelegateTypeInstance;
closureState.mClosureInstanceInfo = lambdaInstance->mMethodInstance->mMethodInfoEx->mClosureInstanceInfo; closureState.mClosureInstanceInfo = lambdaInstance->mMethodInstance->mMethodInfoEx->mClosureInstanceInfo;
mCurMethodState->mMixinState = lambdaInstance->mDeclMixinState; mCurMethodState->mMixinState = lambdaInstance->mDeclMixinState;

View file

@ -1773,7 +1773,7 @@ public:
HashSet<int> mDefinedStrings; HashSet<int> mDefinedStrings;
public: public:
BfVDataModule(BfContext* context) : BfModule(context, "vdata") BfVDataModule(BfContext* context) : BfModule(context, StringImpl::MakeRef("vdata"))
{ {
} }
}; };

View file

@ -59,10 +59,10 @@ void MemReporter::Report(int depth, Entry* entry)
} }
} }
void MemReporter::BeginSection(const StringImpl& name) void MemReporter::BeginSection(const StringView& name)
{ {
Entry** entryPtr; Entry** entryPtr;
if (!mCurEntry->mChildren.TryAdd(name, NULL, &entryPtr)) if (!mCurEntry->mChildren.TryAdd(StringImpl::MakeRef(name), NULL, &entryPtr))
{ {
mCurEntry = *entryPtr; mCurEntry = *entryPtr;
mCurEntry->mCount++; mCurEntry->mCount++;
@ -82,7 +82,7 @@ void MemReporter::Add(int size)
mCurEntry->mSize += size; mCurEntry->mSize += size;
} }
void MemReporter::Add(const StringImpl& name, int size) void MemReporter::Add(const StringView& name, int size)
{ {
BeginSection(name); BeginSection(name);
Add(size); Add(size);

View file

@ -44,9 +44,9 @@ public:
MemReporter(); MemReporter();
~MemReporter(); ~MemReporter();
void BeginSection(const StringImpl& name); void BeginSection(const StringView& name);
void Add(int size); void Add(int size);
void Add(const StringImpl& name, int size); void Add(const StringView& name, int size);
template <typename T> template <typename T>
void AddVec(const T& vec, bool addContainerSize = true) void AddVec(const T& vec, bool addContainerSize = true)
@ -55,7 +55,7 @@ public:
} }
template <typename T> template <typename T>
void AddVec(const StringImpl& name, const T& vec, bool addContainerSize = true) void AddVec(const StringView& name, const T& vec, bool addContainerSize = true)
{ {
BeginSection(name); BeginSection(name);
Add((addContainerSize ? sizeof(T) : 0) + (int)vec.mAllocSize * sizeof(typename T::value_type)); Add((addContainerSize ? sizeof(T) : 0) + (int)vec.mAllocSize * sizeof(typename T::value_type));
@ -79,7 +79,7 @@ public:
} }
template <typename T> template <typename T>
void AddVecPtr(const StringImpl& name, const Array<T>& vec, bool addContainerSize = true) void AddVecPtr(const StringView& name, const Array<T>& vec, bool addContainerSize = true)
{ {
Add(name, (addContainerSize ? sizeof(T) : 0) + Add(name, (addContainerSize ? sizeof(T) : 0) +
(int)vec.mAllocSize * sizeof(T) + (int)vec.mAllocSize * sizeof(T) +
@ -87,7 +87,7 @@ public:
} }
template <typename T> template <typename T>
void AddMap(const StringImpl& name, const T& map, bool addContainerSize = true) void AddMap(const StringView& name, const T& map, bool addContainerSize = true)
{ {
Add(name, (addContainerSize ? sizeof(T) : 0) + map.mAllocSize * (sizeof(typename T::EntryPair) + sizeof(typename T::int_cosize))); Add(name, (addContainerSize ? sizeof(T) : 0) + map.mAllocSize * (sizeof(typename T::EntryPair) + sizeof(typename T::int_cosize)));
} }
@ -99,7 +99,7 @@ public:
} }
template <typename T> template <typename T>
void AddHashSet(const StringImpl& name, const T& map, bool addContainerSize = true) void AddHashSet(const StringView& name, const T& map, bool addContainerSize = true)
{ {
Add(name, (addContainerSize ? sizeof(T) : 0) + map.mAllocSize * (sizeof(typename T::Entry) + sizeof(typename T::int_cosize))); Add(name, (addContainerSize ? sizeof(T) : 0) + map.mAllocSize * (sizeof(typename T::Entry) + sizeof(typename T::int_cosize)));
} }
@ -115,7 +115,7 @@ public:
Add((addContainerSize ? sizeof(StringImpl) : 0) + (int)str.GetAllocSize()); Add((addContainerSize ? sizeof(StringImpl) : 0) + (int)str.GetAllocSize());
} }
void AddStr(const StringImpl& name, const StringImpl& str, bool addContainerSize = true) void AddStr(const StringView& name, const StringImpl& str, bool addContainerSize = true)
{ {
Add(name, (addContainerSize ? sizeof(StringImpl) : 0) + (int)str.GetAllocSize()); Add(name, (addContainerSize ? sizeof(StringImpl) : 0) + (int)str.GetAllocSize());
} }
@ -125,7 +125,7 @@ public:
template <typename T> template <typename T>
void AddBumpAlloc(const StringImpl& name, const T& alloc) void AddBumpAlloc(const StringView& name, const T& alloc)
{ {
BeginSection(name); BeginSection(name);

View file

@ -390,7 +390,7 @@ String DbgSubprogram::ToString()
{ {
if (mLinkName[0] == '<') if (mLinkName[0] == '<')
return mLinkName; return mLinkName;
str = BfDemangler::Demangle(mLinkName, language); str = BfDemangler::Demangle(StringImpl::MakeRef(mLinkName), language);
// Strip off the params since we need to generate those ourselves // Strip off the params since we need to generate those ourselves
int parenPos = (int)str.IndexOf('('); int parenPos = (int)str.IndexOf('(');
if (parenPos != -1) if (parenPos != -1)
@ -776,6 +776,13 @@ bool DbgSubprogram::ThisIsSplat()
return strncmp(mBlock.mVariables.mHead->mName, "$this$", 6) == 0; return strncmp(mBlock.mVariables.mHead->mName, "$this$", 6) == 0;
} }
bool DbgSubprogram::IsLambda()
{
if (mName == NULL)
return false;
return StringView(mName).Contains('$');
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
DbgSubprogram::~DbgSubprogram() DbgSubprogram::~DbgSubprogram()
@ -863,7 +870,7 @@ void DbgSrcFile::RehupLineData()
for (int idx = 0; idx < (int)mLineDataRefs.size(); idx++) for (int idx = 0; idx < (int)mLineDataRefs.size(); idx++)
{ {
auto dbgSubprogram = mLineDataRefs[idx]; auto dbgSubprogram = mLineDataRefs[idx];
if (dbgSubprogram->mWasModuleHotReplaced) if (dbgSubprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_None)
{ {
mLineDataRefs.RemoveAtFast(idx); mLineDataRefs.RemoveAtFast(idx);
idx--; idx--;
@ -1548,6 +1555,7 @@ String DbgType::ToString(DbgLanguage language, bool allowDirectBfObject)
else else
return mParent->ToString(language) + "::" + nameP; return mParent->ToString(language) + "::" + nameP;
} }
switch (mTypeCode) switch (mTypeCode)
{ {
@ -1999,6 +2007,39 @@ DbgModule::~DbgModule()
delete data; delete data;
} }
DbgSubprogram* DbgModule::FindSubprogram(DbgType* dbgType, const char * methodName)
{
dbgType = dbgType->GetPrimaryType();
dbgType->PopulateType();
if (dbgType->mNeedsGlobalsPopulated)
PopulateTypeGlobals(dbgType);
for (auto methodNameEntry : dbgType->mMethodNameList)
{
if ((methodNameEntry->mCompileUnitId != -1) && (strcmp(methodNameEntry->mName, methodName) == 0))
{
// If we hot-replaced this type then we replaced and parsed all the methods too
if (!dbgType->mCompileUnit->mDbgModule->mIsHotObjectFile)
dbgType->mCompileUnit->mDbgModule->MapCompileUnitMethods(methodNameEntry->mCompileUnitId);
methodNameEntry->mCompileUnitId = -1;
}
}
DbgSubprogram* result = NULL;
for (auto method : dbgType->mMethodList)
{
if (strcmp(method->mName, methodName) == 0)
{
method->PopulateSubprogram();
if ((result == NULL) || (method->mBlock.mLowPC != 0))
result = method;
}
}
return result;
}
void DbgModule::Fail(const StringImpl& error) void DbgModule::Fail(const StringImpl& error)
{ {
if (mFailMsgPtr != NULL) if (mFailMsgPtr != NULL)
@ -4960,7 +5001,8 @@ void DbgModule::HotReplaceType(DbgType* newType)
HashSet<DbgSrcFile*> checkedFiles; HashSet<DbgSrcFile*> checkedFiles;
for (auto method : primaryType->mMethodList) for (auto method : primaryType->mMethodList)
{ {
method->mWasModuleHotReplaced = true; //method->mWasModuleHotReplaced = true;
method->mHotReplaceKind = DbgSubprogram::HotReplaceKind_Orphaned; // May be temporarily orphaned
if (method->mLineInfo == NULL) if (method->mLineInfo == NULL)
continue; continue;
@ -5014,35 +5056,154 @@ void DbgModule::HotReplaceType(DbgType* newType)
primaryType->mHotReplacedMethodList.PushFront(method); primaryType->mHotReplacedMethodList.PushFront(method);
mHotPrimaryTypes.Add(primaryType); mHotPrimaryTypes.Add(primaryType);
} }
Dictionary<StringView, DbgSubprogram*> oldProgramMap;
for (auto oldMethod : primaryType->mHotReplacedMethodList)
{
oldMethod->PopulateSubprogram();
if (oldMethod->mBlock.IsEmpty())
continue;
auto symInfo = mDebugTarget->mSymbolMap.Get(oldMethod->mBlock.mLowPC);
if (symInfo != NULL)
{
oldProgramMap.TryAdd(symInfo->mName, oldMethod);
}
}
bool setHotJumpFailed = false; bool setHotJumpFailed = false;
while (!newType->mMethodList.IsEmpty()) while (!newType->mMethodList.IsEmpty())
{ {
DbgSubprogram* newMethod = newType->mMethodList.PopFront(); DbgSubprogram* newMethod = newType->mMethodList.PopFront();
if (!newMethod->mBlock.IsEmpty()) if (!newMethod->mBlock.IsEmpty())
{ {
newMethod->PopulateSubprogram(); newMethod->PopulateSubprogram();
bool found = false; auto symInfo = mDebugTarget->mSymbolMap.Get(newMethod->mBlock.mLowPC);
for (auto oldMethod : primaryType->mHotReplacedMethodList) if (symInfo != NULL)
{ {
if (oldMethod->mBlock.IsEmpty()) DbgSubprogram* oldMethod = NULL;
continue; if (oldProgramMap.TryGetValue(symInfo->mName, &oldMethod))
if (oldMethod->Equals(newMethod))
{ {
if (!setHotJumpFailed) bool doHotJump = false;
if (oldMethod->Equals(newMethod))
{ {
if (!mDebugger->SetHotJump(oldMethod, newMethod)) doHotJump = true;
setHotJumpFailed = true; }
oldMethod->mWasHotReplaced = true; else
} {
// When mangles match but the actual signatures don't match, that can mean that the call signature was changed
// and thus it's actually a different method and shouldn't hot jump OR it could be lambda whose captures changed.
// When the lambda captures change, the user didn't actually enter a different signature so we want to do a hard
// fail if the old code gets called to avoid confusion of "why aren't my changes working?"
// If we removed captures then we can still do the hot jump. Otherwise we have to fail...
doHotJump = false;
if ((oldMethod->IsLambda()) && (oldMethod->GetParamCount() == 0) && (newMethod->GetParamCount() == 0) &&
(oldMethod->mHasThis) && (newMethod->mHasThis))
{
auto oldParam = oldMethod->mParams.front();
auto newParam = newMethod->mParams.front();
if ((oldParam->mType->IsPointer()) && (newParam->mType->IsPointer()))
{
auto oldType = oldParam->mType->mTypeParam->GetPrimaryType();
auto newType = newParam->mType->mTypeParam->GetPrimaryType();
if ((oldType->IsStruct()) && (newType->IsStruct()))
{
bool wasMatch = true;
auto oldMember = oldType->mMemberList.front();
auto newMember = newType->mMemberList.front();
while (newMember != NULL)
{
if (oldMember == NULL)
{
wasMatch = false;
break;
}
if ((oldMember->mName == NULL) || (newMember->mName == NULL))
{
wasMatch = false;
break;
}
if (strcmp(oldMember->mName, newMember->mName) != 0)
{
wasMatch = false;
break;
}
if (!oldMember->mType->Equals(newMember->mType))
{
wasMatch = false;
break;
}
oldMember = oldMember->mNext;
newMember = newMember->mNext;
}
if (wasMatch)
doHotJump = true;
}
}
if (!doHotJump)
{
mDebugTarget->mDebugger->PhysSetBreakpoint(oldMethod->mBlock.mLowPC);
oldMethod->mHotReplaceKind = DbgSubprogram::HotReplaceKind_Invalid;
}
}
}
if (doHotJump)
{
if (!setHotJumpFailed)
{
if (!mDebugger->SetHotJump(oldMethod, newMethod->mBlock.mLowPC, (int)(newMethod->mBlock.mHighPC - newMethod->mBlock.mLowPC)))
setHotJumpFailed = true;
}
oldMethod->mHotReplaceKind = DbgSubprogram::HotReplaceKind_Replaced;
}
} }
} }
} }
newMethod->mParentType = primaryType; newMethod->mParentType = primaryType;
primaryType->mMethodList.PushBack(newMethod); primaryType->mMethodList.PushBack(newMethod);
} }
//mDebugTarget->mSymbolMap.Get()
// bool setHotJumpFailed = false;
// while (!newType->mMethodList.IsEmpty())
// {
// DbgSubprogram* newMethod = newType->mMethodList.PopFront();
// if (!newMethod->mBlock.IsEmpty())
// {
// newMethod->PopulateSubprogram();
//
// bool found = false;
// for (auto oldMethod : primaryType->mHotReplacedMethodList)
// {
// if (oldMethod->mBlock.IsEmpty())
// continue;
// if (oldMethod->Equals(newMethod))
// {
// if (!setHotJumpFailed)
// {
// if (!mDebugger->SetHotJump(oldMethod, newMethod))
// setHotJumpFailed = true;
// oldMethod->mWasHotReplaced = true;
// }
// }
// }
// }
// newMethod->mParentType = primaryType;
// primaryType->mMethodList.PushBack(newMethod);
// }
primaryType->mCompileUnit->mWasHotReplaced = true; primaryType->mCompileUnit->mWasHotReplaced = true;
primaryType->mNeedsGlobalsPopulated = newType->mNeedsGlobalsPopulated; primaryType->mNeedsGlobalsPopulated = newType->mNeedsGlobalsPopulated;

View file

@ -358,6 +358,14 @@ public:
}; };
#endif #endif
enum HotReplaceKind : uint8
{
HotReplaceKind_None = 0,
HotReplaceKind_Replaced = 1,
HotReplaceKind_Orphaned = 2, // Module was hot replaced but a new version of the subprogram wasn't found
HotReplaceKind_Invalid = 3 // Mangles matched but arguments were incompatible
};
const char* mName; const char* mName;
const char* mLinkName; const char* mLinkName;
int mTemplateNameIdx; int mTemplateNameIdx;
@ -376,8 +384,7 @@ public:
bool mVirtual; bool mVirtual;
bool mHasThis; bool mHasThis;
bool mNeedLineDataFixup; bool mNeedLineDataFixup;
bool mWasHotReplaced; HotReplaceKind mHotReplaceKind;
bool mWasModuleHotReplaced; // Module was hot replaced but a new version of the subprogram wasn't found
bool mIsOptimized; bool mIsOptimized;
bool mHasLineAddrGaps; // There are gaps of addresses which are not covered by lineinfo bool mHasLineAddrGaps; // There are gaps of addresses which are not covered by lineinfo
DbgLineInfo* mLineInfo; DbgLineInfo* mLineInfo;
@ -397,8 +404,7 @@ public:
mLinkName = NULL; mLinkName = NULL;
mHasThis = false; mHasThis = false;
mNeedLineDataFixup = true; mNeedLineDataFixup = true;
mWasHotReplaced = false; mHotReplaceKind = HotReplaceKind_None;
mWasModuleHotReplaced = false;
mHasLineAddrGaps = false; mHasLineAddrGaps = false;
mPrologueSize = -1; mPrologueSize = -1;
mParentType = NULL; mParentType = NULL;
@ -427,6 +433,7 @@ public:
String GetParamName(int paramIdx); String GetParamName(int paramIdx);
bool IsGenericMethod(); bool IsGenericMethod();
bool ThisIsSplat(); bool ThisIsSplat();
bool IsLambda();
DbgSubprogram* GetRootInlineParent() DbgSubprogram* GetRootInlineParent()
{ {
@ -1201,6 +1208,7 @@ public:
virtual String GetOldSourceCommand(const StringImpl& path) { return ""; } virtual String GetOldSourceCommand(const StringImpl& path) { return ""; }
virtual bool DbgIsStrMutable(const char* str) { return true; } // Always assume its a copy virtual bool DbgIsStrMutable(const char* str) { return true; } // Always assume its a copy
virtual addr_target LocateSymbol(const StringImpl& name) { return 0; } virtual addr_target LocateSymbol(const StringImpl& name) { return 0; }
virtual DbgSubprogram* FindSubprogram(DbgType* dbgType, const char* methodName);
void Fail(const StringImpl& error); void Fail(const StringImpl& error);
void FindTemplateStr(const char*& name, int& templateNameIdx); void FindTemplateStr(const char*& name, int& templateNameIdx);

View file

@ -128,7 +128,7 @@ void DbgHotScanner::PopulateHotCallstacks()
{ {
auto subProgram = stackFrame->mSubProgram; auto subProgram = stackFrame->mSubProgram;
if (subProgram->mWasHotReplaced) if (subProgram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced)
subProgram = mDebugger->TryFollowHotJump(subProgram, stackFrame->mRegisters.GetPC()); subProgram = mDebugger->TryFollowHotJump(subProgram, stackFrame->mRegisters.GetPC());
AddSubProgram(subProgram, false, ""); AddSubProgram(subProgram, false, "");

View file

@ -2052,14 +2052,14 @@ void BlCodeView::CreateLinkerSymStream()
ENVBLOCKSYM envBlock = { 0 }; ENVBLOCKSYM envBlock = { 0 };
envBlock.rectyp = S_ENVBLOCK; envBlock.rectyp = S_ENVBLOCK;
str = "cwd"; str.Append(0); str = "cwd"; str.Append('\0');
str += cwd; str.Append(0); str += cwd; str.Append('\0');
str += "exe"; str.Append(0); str += "exe"; str.Append('\0');
str += moduleFileName; str.Append(0); str += moduleFileName; str.Append('\0');
str += "pdb"; str.Append(0); str += "pdb"; str.Append('\0');
str += mMsf.mFileName; str.Append(0); str += mMsf.mFileName; str.Append('\0');
str += "cmd"; str.Append(0); str += "cmd"; str.Append('\0');
str += GetCommandLineA(); str.Append(0); str += GetCommandLineA(); str.Append('\0');
OUT_WITH_STR(ENVBLOCKSYM, envBlock, rgsz); OUT_WITH_STR(ENVBLOCKSYM, envBlock, rgsz);
for (auto segment : mContext->mSegments) for (auto segment : mContext->mSegments)

View file

@ -1863,10 +1863,20 @@ bool WinDebugger::DoUpdate()
bool isNonDebuggerBreak = false; bool isNonDebuggerBreak = false;
if (wasDebugBreakpoint) if (wasDebugBreakpoint)
{ {
// Go ahead and set EIP back one instruction // Go ahead and set EIP back one instruction
BF_CONTEXT_IP(lcContext)--; BF_CONTEXT_IP(lcContext)--;
BF_SetThreadContext(threadInfo->mHThread, &lcContext); BF_SetThreadContext(threadInfo->mHThread, &lcContext);
if ((dwSubprogram != NULL) && (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Invalid) &&
(pcAddress == dwSubprogram->mBlock.mLowPC))
{
BfLogDbg("Hit HotReplaceKind_Invalid breakpoint\n");
mRunState = RunState_Paused;
mDebugManager->mOutMessages.push_back("error This lambda was replaced by a new version that has incompatible captures. A program restart is required.");
PhysRemoveBreakpoint(pcAddress);
break;
}
} }
else else
{ {
@ -2223,9 +2233,9 @@ bool WinDebugger::DoUpdate()
} }
} }
else else
{ {
BfLogDbg("Ignoring break (old or ignored breakpoint)\n"); BfLogDbg("Ignoring break (old or ignored breakpoint)\n");
mRunState = RunState_Running; mRunState = RunState_Running;
} }
} }
@ -2363,7 +2373,7 @@ bool WinDebugger::DoUpdate()
DbgSubprogram* dwSubprogram = NULL; DbgSubprogram* dwSubprogram = NULL;
DbgLineData* dwLineData = FindLineDataAtAddress(pcAddress, &dwSubprogram, NULL, NULL, DbgOnDemandKind_LocalOnly); DbgLineData* dwLineData = FindLineDataAtAddress(pcAddress, &dwSubprogram, NULL, NULL, DbgOnDemandKind_LocalOnly);
if ((dwSubprogram != NULL) && (pcAddress == dwSubprogram->mBlock.mLowPC) && (dwSubprogram->mWasHotReplaced)) if ((dwSubprogram != NULL) && (pcAddress == dwSubprogram->mBlock.mLowPC) && (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced))
{ {
BfLogDbg("Stepping through hot thunk\n"); BfLogDbg("Stepping through hot thunk\n");
mRunState = RunState_Running; mRunState = RunState_Running;
@ -2413,7 +2423,7 @@ bool WinDebugger::DoUpdate()
} }
else if (dwSubprogram != NULL) else if (dwSubprogram != NULL)
{ {
if ((dwSubprogram->mWasHotReplaced) && ((mStepType == StepType_StepInto) || (mStepType == StepType_StepInto_Unfiltered))) if ((dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) && ((mStepType == StepType_StepInto) || (mStepType == StepType_StepInto_Unfiltered)))
{ {
SingleStepX86(); SingleStepX86();
} }
@ -2963,7 +2973,7 @@ void WinDebugger::CheckBreakpoint(WdBreakpoint* wdBreakpoint, DbgSrcFile* srcFil
if ((foundInSequence) && (subProgram != lastFoundSubprogram)) if ((foundInSequence) && (subProgram != lastFoundSubprogram))
foundInSequence = false; foundInSequence = false;
if ((subProgram->mWasHotReplaced) && (address < subProgram->mBlock.mLowPC + sizeof(HotJumpOp))) if ((subProgram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) && (address < subProgram->mBlock.mLowPC + sizeof(HotJumpOp)))
{ {
// If this breakpoint ends up on the hot jmp instruction // If this breakpoint ends up on the hot jmp instruction
continue; continue;
@ -2973,7 +2983,7 @@ void WinDebugger::CheckBreakpoint(WdBreakpoint* wdBreakpoint, DbgSrcFile* srcFil
{ {
lastFoundSubprogram = subProgram; lastFoundSubprogram = subProgram;
if ((subProgram != NULL) && (subProgram->mWasHotReplaced) && (address == subProgram->mBlock.mLowPC)) if ((subProgram != NULL) && (subProgram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) && (address == subProgram->mBlock.mLowPC))
{ {
// This instruction is actually the hot jump, we don't need a breakpoint here // This instruction is actually the hot jump, we don't need a breakpoint here
foundInSequence = true; foundInSequence = true;
@ -4957,7 +4967,7 @@ bool WinDebugger::RollBackStackFrame(CPURegisters* registers, bool isStackStart)
return mDebugTarget->RollBackStackFrame(registers, NULL, isStackStart); return mDebugTarget->RollBackStackFrame(registers, NULL, isStackStart);
} }
bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSubprogram) bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, addr_target newTarget, int newTargetSize)
{ {
//AutoCrit autoCrit(mDebugManager->mCritSect); //AutoCrit autoCrit(mDebugManager->mCritSect);
BF_ASSERT(mDebugManager->mCritSect.mLockCount == 1); BF_ASSERT(mDebugManager->mCritSect.mLockCount == 1);
@ -4968,14 +4978,14 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub
if (jmpInstEnd > oldSubprogram->mBlock.mHighPC) if (jmpInstEnd > oldSubprogram->mBlock.mHighPC)
{ {
if ((oldSubprogram->mBlock.mHighPC - oldSubprogram->mBlock.mLowPC == 1) && if ((oldSubprogram->mBlock.mHighPC - oldSubprogram->mBlock.mLowPC == 1) &&
(newSubprogram->mBlock.mHighPC - newSubprogram->mBlock.mLowPC == 1)) (newTargetSize == 1))
return true; // Special case for just stub 'ret' methods return true; // Special case for just stub 'ret' methods
String err = StrFormat("Failed to hot replace method, method '%s' too small to insert hot thunk", newSubprogram->ToString().c_str()); String err = StrFormat("Failed to hot replace method, method '%s' too small to insert hot thunk", oldSubprogram->ToString().c_str());
Fail(err); Fail(err);
return false; return false;
} }
if (!oldSubprogram->mWasHotReplaced) if (oldSubprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_Replaced)
{ {
for (int threadIdx = 0; threadIdx < (int)mThreadList.size(); threadIdx++) for (int threadIdx = 0; threadIdx < (int)mThreadList.size(); threadIdx++)
{ {
@ -5068,7 +5078,7 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub
HotJumpOp jumpOp; HotJumpOp jumpOp;
jumpOp.mOpCode = 0xE9; jumpOp.mOpCode = 0xE9;
jumpOp.mRelTarget = newSubprogram->mBlock.mLowPC - oldSubprogram->mBlock.mLowPC - sizeof(HotJumpOp); jumpOp.mRelTarget = newTarget - oldSubprogram->mBlock.mLowPC - sizeof(HotJumpOp);
WriteMemory(oldSubprogram->mBlock.mLowPC, jumpOp); WriteMemory(oldSubprogram->mBlock.mLowPC, jumpOp);
::FlushInstructionCache(mProcessInfo.hProcess, (void*)(intptr)oldSubprogram->mBlock.mLowPC, sizeof(HotJumpOp)); ::FlushInstructionCache(mProcessInfo.hProcess, (void*)(intptr)oldSubprogram->mBlock.mLowPC, sizeof(HotJumpOp));
return true; return true;
@ -5076,7 +5086,7 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub
DbgSubprogram* WinDebugger::TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr) DbgSubprogram* WinDebugger::TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr)
{ {
if (!subprogram->mWasHotReplaced) if (subprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_Replaced)
return subprogram; return subprogram;
if (addr != subprogram->mBlock.mLowPC) if (addr != subprogram->mBlock.mLowPC)
@ -10794,14 +10804,14 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
if (!dbgModule->mDisplayName.empty()) if (!dbgModule->mDisplayName.empty())
demangledName = dbgModule->mDisplayName + "!" + demangledName; demangledName = dbgModule->mDisplayName + "!" + demangledName;
if (dwSubprogram->mWasHotReplaced) if ((dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) || (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Invalid))
demangledName = "#" + demangledName; demangledName = "#" + demangledName;
if (dbgModule->HasPendingDebugInfo()) if (dbgModule->HasPendingDebugInfo())
*outFlags |= FrameFlags_HasPendingDebugInfo; *outFlags |= FrameFlags_HasPendingDebugInfo;
if (dbgModule->CanGetOldSource()) if (dbgModule->CanGetOldSource())
*outFlags |= FrameFlags_CanGetOldSource; *outFlags |= FrameFlags_CanGetOldSource;
if (dwSubprogram->mWasHotReplaced) if ((dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) || (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Invalid))
*outFlags |= FrameFlags_WasHotReplaced; *outFlags |= FrameFlags_WasHotReplaced;
if ((dwLineData != NULL) && (dwSrcFile != NULL)) if ((dwLineData != NULL) && (dwSrcFile != NULL))

View file

@ -479,7 +479,7 @@ public:
bool PopulateRegisters(CPURegisters* registers, BF_CONTEXT& lcContext); bool PopulateRegisters(CPURegisters* registers, BF_CONTEXT& lcContext);
virtual bool PopulateRegisters(CPURegisters* registers); virtual bool PopulateRegisters(CPURegisters* registers);
bool RollBackStackFrame(CPURegisters* registers, bool isStackStart); bool RollBackStackFrame(CPURegisters* registers, bool isStackStart);
bool SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSubprogram); bool SetHotJump(DbgSubprogram* oldSubprogram, addr_target newTarget, int newTargetSize);
DbgSubprogram* TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr); DbgSubprogram* TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr);
bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue()); bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue());