From 2f01cc14dd5d5a6f2f0a9d7d2d9be2f964e6adb7 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 3 Sep 2019 11:17:13 -0700 Subject: [PATCH] Beefy::String changes, lambda hotswap fixes Changed some string internals related to StringViewsma Added an "incompatible capture" error for lambdas when the captures change --- BeefTools/BeefInstall/StubUI/src/Board.bf | 68 +++++- BeefySysLib/util/Dictionary.h | 9 + BeefySysLib/util/PerfTimer.h | 2 +- BeefySysLib/util/String.cpp | 55 ++++- BeefySysLib/util/String.h | 66 ++++-- IDE/BeefProj.toml | 2 +- IDE/Tests/Test1/scripts/HotSwap_Lambdas01.txt | 28 +++ IDE/Tests/Test1/src/HotSwap_Lambdas01.bf | 62 ++++++ IDE/Tests/Test1/src/Program.bf | 1 + IDE/mintest/BeefSpace.toml | 1 - IDE/mintest/src/main3.bf | 98 +++------ IDE/src/IDEApp.bf | 5 +- IDE/src/ScriptManager.bf | 5 + IDEHelper/COFF.h | 2 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 16 +- IDEHelper/Compiler/BfModule.cpp | 11 +- IDEHelper/Compiler/BfModule.h | 2 +- IDEHelper/Compiler/MemReporter.cpp | 6 +- IDEHelper/Compiler/MemReporter.h | 16 +- IDEHelper/DbgModule.cpp | 193 ++++++++++++++++-- IDEHelper/DbgModule.h | 16 +- IDEHelper/HotScanner.cpp | 2 +- IDEHelper/Linker/BlCodeView.cpp | 16 +- IDEHelper/WinDebugger.cpp | 40 ++-- IDEHelper/WinDebugger.h | 2 +- 25 files changed, 544 insertions(+), 180 deletions(-) create mode 100644 IDE/Tests/Test1/scripts/HotSwap_Lambdas01.txt create mode 100644 IDE/Tests/Test1/src/HotSwap_Lambdas01.bf diff --git a/BeefTools/BeefInstall/StubUI/src/Board.bf b/BeefTools/BeefInstall/StubUI/src/Board.bf index a6be7a10..8199bac7 100644 --- a/BeefTools/BeefInstall/StubUI/src/Board.bf +++ b/BeefTools/BeefInstall/StubUI/src/Board.bf @@ -4,6 +4,7 @@ using Beefy.gfx; using System.Diagnostics; using System; using System.IO; +using System.Threading; namespace BIStubUI { @@ -202,10 +203,13 @@ namespace BIStubUI float mEatPct; int mCloseTicks; + int mInstallTicks; public bool mIsClosed; + bool mUninstallDone; public bool mInstalling; - public float mInstallPct = 0.5f; + public bool mUninstalling; + public float mInstallPct; public this() { @@ -256,7 +260,7 @@ namespace BIStubUI mCancelButton.mImageHi = Images.sButtonHi; mCancelButton.mOnMouseClick.Add(new (mouseArgs) => { - gApp.mCancelling = true; + //gApp.mCancelling = true; }); mCancelButton.mMouseInsets = new Insets(4, 4, 4, 4); AddWidget(mCancelButton); @@ -289,6 +293,12 @@ namespace BIStubUI mInstallPathBox.mInstallPath.Append(@"\BeefLang"); } + void Uninstall() + { + Thread.Sleep(10000); + mUninstallDone = true; + } + void StartInstall() { mInstalling = true; @@ -320,13 +330,15 @@ namespace BIStubUI if (mInstalling) { - float installDiv = 1000.0f; + //float installDiv = 1000.0f; //mInstallPct = (mUpdateCnt % installDiv) / installDiv; //mInstallPct = 1.0f; float totalWidth = 410; float fillWidth = totalWidth * (mInstallPct*0.9f + 0.1f); + if (mUninstalling) + fillWidth = totalWidth * mInstallPct; float barX = 200; float barY = 280; @@ -338,15 +350,19 @@ namespace BIStubUI Color colorLeft = 0x800288E9; Color colorRight = 0x80FFFFFF; + if (gApp.mClosing) + { + colorLeft = 0x80000000; + colorRight = 0x800288E9; + } 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++) { Images.sPBBarHilite.mPixelSnapping = .Never; 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); @@ -395,6 +411,15 @@ namespace BIStubUI base.DrawAll(g); } + public bool IsDecompressing + { + get + { + //return gApp. + return false; + } + } + public override void Update() { base.Update(); @@ -403,6 +428,34 @@ namespace BIStubUI 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) { gApp.mSoundManager.PlaySound(Sounds.sAbort); @@ -427,6 +480,9 @@ namespace BIStubUI return; } + if (mInstalling) + mInstallTicks++; + if (mUpdateCnt == 1) gApp.mSoundManager.PlaySound(Sounds.sBoing); diff --git a/BeefySysLib/util/Dictionary.h b/BeefySysLib/util/Dictionary.h index 062fa22f..e431e9e3 100644 --- a/BeefySysLib/util/Dictionary.h +++ b/BeefySysLib/util/Dictionary.h @@ -483,6 +483,15 @@ public: return true; } +// template +// 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 bool TryAddRaw(const TKey& key, TKey** keyPtr, TValue** valuePtr) { diff --git a/BeefySysLib/util/PerfTimer.h b/BeefySysLib/util/PerfTimer.h index 6f4aab65..18f69a1f 100644 --- a/BeefySysLib/util/PerfTimer.h +++ b/BeefySysLib/util/PerfTimer.h @@ -157,7 +157,7 @@ public: String mName; public: - DebugTimeGuard(int maxTicks, const StringImpl& name = "DebugTimeGuard") + DebugTimeGuard(int maxTicks, const StringImpl& name = StringImpl::MakeRef("DebugTimeGuard")) { mName = name; mMaxTicks = maxTicks; diff --git a/BeefySysLib/util/String.cpp b/BeefySysLib/util/String.cpp index 7efe5876..d3fa592e 100644 --- a/BeefySysLib/util/String.cpp +++ b/BeefySysLib/util/String.cpp @@ -129,6 +129,16 @@ String Beefy::operator+(const StringImpl& lhs, const StringView& rhs) 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 str; @@ -138,6 +148,26 @@ String Beefy::operator+(const StringImpl& lhs, char rhs) 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) { 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); } +void StringImpl::Append(const char* appendPtr) +{ + Append(appendPtr, (int)strlen(appendPtr)); +} + void StringImpl::Append(const char* appendPtr, intptr 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); } -void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl & replace) +void StringImpl::ReplaceLargerHelper(const StringView& find, const StringView& replace) { Array replaceEntries; @@ -546,7 +581,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl & 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); startIdx += find.mLength - 1; @@ -561,7 +596,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl & if (needSize > GetAllocSize()) Realloc((int_strsize)needSize); - auto replacePtr = replace.GetPtr(); + auto replacePtr = replace.mPtr; auto ptr = GetMutablePtr(); intptr lastDestStartIdx = destLength; @@ -585,7 +620,7 @@ void StringImpl::ReplaceLargerHelper(const StringImpl & find, const StringImpl & 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) { @@ -594,8 +629,8 @@ void StringImpl::Replace(const StringImpl & find, const StringImpl & replace) } auto ptr = GetMutablePtr(); - auto findPtr = find.GetPtr(); - auto replacePtr = replace.GetPtr(); + auto findPtr = find.mPtr; + auto replacePtr = replace.mPtr; int_strsize inIdx = 0; int_strsize outIdx = 0; @@ -693,7 +728,7 @@ bool StringImpl::HasMultibyteChars() 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++) { @@ -704,15 +739,15 @@ intptr StringImpl::IndexOf(const StringImpl& subStr, bool ignoreCase) const 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); } -intptr StringImpl::IndexOf(const StringImpl& subStr, int64 startIdx) const +intptr StringImpl::IndexOf(const StringView& subStr, int64 startIdx) const { const char* ptr = GetPtr(); - const char* subStrPtr = subStr.GetPtr(); + const char* subStrPtr = subStr.mPtr; for (intptr ofs = (intptr)startIdx; ofs <= mLength - subStr.mLength; ofs++) { if (strncmp(ptr + ofs, subStrPtr, subStr.mLength) == 0) diff --git a/BeefySysLib/util/String.h b/BeefySysLib/util/String.h index ab192d4f..ea23aa64 100644 --- a/BeefySysLib/util/String.h +++ b/BeefySysLib/util/String.h @@ -33,6 +33,12 @@ public: StringView(const StringImpl& str, int offset); 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) { this->mPtr = ptr; @@ -54,6 +60,13 @@ public: 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; @@ -339,6 +352,26 @@ protected: 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) { // 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); void Reserve(intptr newSize); + void Append(const char* appendPtr); void Append(const char* appendPtr, intptr length); void Append(const StringView& str); void Append(const StringImpl& str); @@ -672,22 +706,22 @@ public: 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) return false; if (comparisonType == CompareKind_OrdinalIgnoreCase) - return EqualsIgnoreCaseHelper(this->GetPtr(), b.GetPtr(), b.mLength); - return EqualsHelper(this->GetPtr(), b.GetPtr(), b.mLength); + return EqualsIgnoreCaseHelper(this->GetPtr(), b.mPtr, 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) return false; if (comparisonType == CompareKind_OrdinalIgnoreCase) - return EqualsIgnoreCaseHelper(this->GetPtr() + this->mLength - b.mLength, b.GetPtr(), b.mLength); - return EqualsHelper(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.mPtr, b.mLength); } bool StartsWith(char c) const @@ -704,8 +738,8 @@ public: return GetPtr()[this->mLength - 1] == c; } - void ReplaceLargerHelper(const StringImpl& find, const StringImpl& replace); - void Replace(const StringImpl& find, const StringImpl& replace); + void ReplaceLargerHelper(const StringView& find, const StringView& replace); + void Replace(const StringView& find, const StringView& replace); void TrimEnd(); void TrimStart(); void Trim(); @@ -721,9 +755,9 @@ public: } bool HasMultibyteChars(); - intptr IndexOf(const StringImpl& subStr, bool ignoreCase = false) const; - intptr IndexOf(const StringImpl& subStr, int32 startIdx) const; - intptr IndexOf(const StringImpl& subStr, int64 startIdx) const; + intptr IndexOf(const StringView& subStr, bool ignoreCase = false) const; + intptr IndexOf(const StringView& subStr, int32 startIdx) const; + intptr IndexOf(const StringView& subStr, int64 startIdx) const; intptr IndexOf(char c, intptr startIdx = 0) const; intptr LastIndexOf(char c) const; intptr LastIndexOf(char c, intptr startCheck) const; @@ -732,8 +766,8 @@ public: { return IndexOf(c) != -1; } - - bool Contains(const StringImpl& str) const + + bool Contains(const StringView& str) const { return IndexOf(str) != -1; } @@ -909,7 +943,7 @@ public: \ using StringImpl::StringImpl; \ using StringImpl::operator=; \ 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 StringImpl& str) : StringImpl(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 StringView& rhs); +String operator+(const StringImpl& lhs, const 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 StringView& lhs, const StringImpl& rhs); diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index 4883d16c..286f7cec 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -27,7 +27,7 @@ TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" 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" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/Tests/Test1/scripts/HotSwap_Lambdas01.txt b/IDE/Tests/Test1/scripts/HotSwap_Lambdas01.txt new file mode 100644 index 00000000..e6904a93 --- /dev/null +++ b/IDE/Tests/Test1/scripts/HotSwap_Lambdas01.txt @@ -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") \ No newline at end of file diff --git a/IDE/Tests/Test1/src/HotSwap_Lambdas01.bf b/IDE/Tests/Test1/src/HotSwap_Lambdas01.bf new file mode 100644 index 00000000..ad4e7922 --- /dev/null +++ b/IDE/Tests/Test1/src/HotSwap_Lambdas01.bf @@ -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(); + } + } +} diff --git a/IDE/Tests/Test1/src/Program.bf b/IDE/Tests/Test1/src/Program.bf index b85da495..8fa1a05e 100644 --- a/IDE/Tests/Test1/src/Program.bf +++ b/IDE/Tests/Test1/src/Program.bf @@ -14,6 +14,7 @@ namespace IDETest HotSwap_Data.Test(); HotSwap_GetUnusued.Test(); HotSwap_Interfaces2.Test(); + HotSwap_Lambdas01.Test(); HotSwap_LocateSym01.Test(); HotSwap_Reflection.Test(); HotSwap_TLS.Test(); diff --git a/IDE/mintest/BeefSpace.toml b/IDE/mintest/BeefSpace.toml index be668c8f..6442203f 100644 --- a/IDE/mintest/BeefSpace.toml +++ b/IDE/mintest/BeefSpace.toml @@ -10,7 +10,6 @@ IntermediateType = "ObjectAndIRCode" ConfigSelections = {mintest2 = {Enabled = false}} [Configs.Debug.Win64] -BfOptimizationLevel = "O0" IntermediateType = "ObjectAndIRCode" COptimizationLevel = "Og" diff --git a/IDE/mintest/src/main3.bf b/IDE/mintest/src/main3.bf index 64b15371..cb9e196c 100644 --- a/IDE/mintest/src/main3.bf +++ b/IDE/mintest/src/main3.bf @@ -87,85 +87,37 @@ struct TestStruct public int mB; } +class Bloozer +{ + int mA; +} + class Blurg { - [Export, CLink, StdCall] - public static void Poof() - { - 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; - } - + delegate void() mFuncA; + delegate void() mFuncB; + public static void Hey() { - float f = 1.2f; - //f = f % 2.3f; + int a = 123; + Blurg blurg = scope .(); + blurg.mFuncA = new () => + { + PrintF("YoA!\n"); + PrintF("A %d!\n", a); + PrintF("Blurg: %p\n", blurg); + }; - TestStruct ts = .(); - //int val = ts..mA; - ts.mA = 123; + blurg.mFuncB = new () => + { + PrintF("YoB!\n"); + }; - GetInt(); - GetInt(); - - VoidCall(); - int val0 = GetInt(); - - Blurg bl = scope .(); - int val = 0; - bl.DoRecurse(0, ref val); - - Test0(); - Test0(); - Test0(); - Test0(); - - Result voidPtrResult = default; - - //void* val = voidPtrResult; - - - //Result ts = .Ok(.()); - - //let val = ts.Get(); - //Snorf.Bloog bl = .(); - - //Poof(); + while (true) + { + blurg.mFuncA(); + blurg.mFuncB(); + } } } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index b6381420..df9673fd 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -3051,7 +3051,7 @@ namespace IDE if (mRunningTestScript) { - if ((mScriptManager.mExpectingError != null) && (text.Contains(mScriptManager.mExpectingError))) + if (mScriptManager.IsErrorExpected(text)) { DeleteAndNullify!(mScriptManager.mExpectingError); OutputLine("Received expected error: {0}", text); @@ -10479,7 +10479,7 @@ namespace IDE } else if (cmd == "error") { - if ((mRunningTestScript) && (!IsCrashDump)) + if ((mRunningTestScript) && (!IsCrashDump) && (!mScriptManager.IsErrorExpected(param))) mScriptManager.Fail(param); bool isFirstMsg = true; @@ -10553,7 +10553,6 @@ namespace IDE if (isFirstMsg) { OutputLineSmart(scope String("ERROR: ", errorMsg)); - Fail(errorMsg); isFirstMsg = false; } else diff --git a/IDE/src/ScriptManager.bf b/IDE/src/ScriptManager.bf index ff41e486..68bae5a2 100644 --- a/IDE/src/ScriptManager.bf +++ b/IDE/src/ScriptManager.bf @@ -177,6 +177,11 @@ namespace IDE //gApp.mRunningTestScript = false; } + public bool IsErrorExpected(StringView err) + { + return (mExpectingError != null) && (err.Contains(mExpectingError)); + } + public void Fail(StringView fmt, params Object[] args) { Fail(scope String()..AppendF(fmt, params args)); diff --git a/IDEHelper/COFF.h b/IDEHelper/COFF.h index 9aa6233e..fc544521 100644 --- a/IDEHelper/COFF.h +++ b/IDEHelper/COFF.h @@ -405,7 +405,7 @@ namespace std { 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)); } }; } diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 5ba15b76..481df8bf 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -9553,7 +9553,9 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam mModule->mBfIRBuilder->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 newTypes; SizedArray origParamTypes; @@ -9598,12 +9600,12 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam methodDef->mName.RemoveToEnd(prevSepPos); } - if (closureTypeInst != NULL) - { - StringT<128> typeInstName; - BfMangler::Mangle(typeInstName,mModule->mCompiler->GetMangleKind(), closureTypeInst); - closureHashCtx.MixinStr(typeInstName); - } +// if (closureTypeInst != NULL) +// { +// StringT<128> typeInstName; +// BfMangler::Mangle(typeInstName,mModule->mCompiler->GetMangleKind(), closureTypeInst); +// closureHashCtx.MixinStr(typeInstName); +// } auto checkMethodState = mModule->mCurMethodState; while (checkMethodState != NULL) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 9113df66..19cc23cf 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -778,11 +778,7 @@ BfModule* gLastCreatedModule = NULL; BfModule::BfModule(BfContext* context, const StringImpl& moduleName) { BfLogSys(context->mSystem, "BfModule::BFModule %p %s\n", this, moduleName.c_str()); - if (moduleName.Contains("_Comparison_")) - { - NOP; - } - + gLastCreatedModule = this; mContext = context; @@ -14930,7 +14926,10 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx) mCurMethodState->mClosureState = &closureState; //closureState.mConstLocals = deferredLocalMethod->mConstLocals; 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; mCurMethodState->mMixinState = lambdaInstance->mDeclMixinState; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index cc26f618..74626b52 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1773,7 +1773,7 @@ public: HashSet mDefinedStrings; public: - BfVDataModule(BfContext* context) : BfModule(context, "vdata") + BfVDataModule(BfContext* context) : BfModule(context, StringImpl::MakeRef("vdata")) { } }; diff --git a/IDEHelper/Compiler/MemReporter.cpp b/IDEHelper/Compiler/MemReporter.cpp index 15a65fa3..afae1de3 100644 --- a/IDEHelper/Compiler/MemReporter.cpp +++ b/IDEHelper/Compiler/MemReporter.cpp @@ -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; - if (!mCurEntry->mChildren.TryAdd(name, NULL, &entryPtr)) + if (!mCurEntry->mChildren.TryAdd(StringImpl::MakeRef(name), NULL, &entryPtr)) { mCurEntry = *entryPtr; mCurEntry->mCount++; @@ -82,7 +82,7 @@ void MemReporter::Add(int size) mCurEntry->mSize += size; } -void MemReporter::Add(const StringImpl& name, int size) +void MemReporter::Add(const StringView& name, int size) { BeginSection(name); Add(size); diff --git a/IDEHelper/Compiler/MemReporter.h b/IDEHelper/Compiler/MemReporter.h index 195b3fd5..ea0ff7ff 100644 --- a/IDEHelper/Compiler/MemReporter.h +++ b/IDEHelper/Compiler/MemReporter.h @@ -44,9 +44,9 @@ public: MemReporter(); ~MemReporter(); - void BeginSection(const StringImpl& name); + void BeginSection(const StringView& name); void Add(int size); - void Add(const StringImpl& name, int size); + void Add(const StringView& name, int size); template void AddVec(const T& vec, bool addContainerSize = true) @@ -55,7 +55,7 @@ public: } template - void AddVec(const StringImpl& name, const T& vec, bool addContainerSize = true) + void AddVec(const StringView& name, const T& vec, bool addContainerSize = true) { BeginSection(name); Add((addContainerSize ? sizeof(T) : 0) + (int)vec.mAllocSize * sizeof(typename T::value_type)); @@ -79,7 +79,7 @@ public: } template - void AddVecPtr(const StringImpl& name, const Array& vec, bool addContainerSize = true) + void AddVecPtr(const StringView& name, const Array& vec, bool addContainerSize = true) { Add(name, (addContainerSize ? sizeof(T) : 0) + (int)vec.mAllocSize * sizeof(T) + @@ -87,7 +87,7 @@ public: } template - 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))); } @@ -99,7 +99,7 @@ public: } template - 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))); } @@ -115,7 +115,7 @@ public: 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()); } @@ -125,7 +125,7 @@ public: template - void AddBumpAlloc(const StringImpl& name, const T& alloc) + void AddBumpAlloc(const StringView& name, const T& alloc) { BeginSection(name); diff --git a/IDEHelper/DbgModule.cpp b/IDEHelper/DbgModule.cpp index 44ac5652..56105196 100644 --- a/IDEHelper/DbgModule.cpp +++ b/IDEHelper/DbgModule.cpp @@ -390,7 +390,7 @@ String DbgSubprogram::ToString() { if (mLinkName[0] == '<') 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 int parenPos = (int)str.IndexOf('('); if (parenPos != -1) @@ -776,6 +776,13 @@ bool DbgSubprogram::ThisIsSplat() return strncmp(mBlock.mVariables.mHead->mName, "$this$", 6) == 0; } +bool DbgSubprogram::IsLambda() +{ + if (mName == NULL) + return false; + return StringView(mName).Contains('$'); +} + ////////////////////////////////////////////////////////////////////////// DbgSubprogram::~DbgSubprogram() @@ -863,7 +870,7 @@ void DbgSrcFile::RehupLineData() for (int idx = 0; idx < (int)mLineDataRefs.size(); idx++) { auto dbgSubprogram = mLineDataRefs[idx]; - if (dbgSubprogram->mWasModuleHotReplaced) + if (dbgSubprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_None) { mLineDataRefs.RemoveAtFast(idx); idx--; @@ -1548,6 +1555,7 @@ String DbgType::ToString(DbgLanguage language, bool allowDirectBfObject) else return mParent->ToString(language) + "::" + nameP; } + switch (mTypeCode) { @@ -1999,6 +2007,39 @@ DbgModule::~DbgModule() 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) { if (mFailMsgPtr != NULL) @@ -4960,7 +5001,8 @@ void DbgModule::HotReplaceType(DbgType* newType) HashSet checkedFiles; for (auto method : primaryType->mMethodList) { - method->mWasModuleHotReplaced = true; + //method->mWasModuleHotReplaced = true; + method->mHotReplaceKind = DbgSubprogram::HotReplaceKind_Orphaned; // May be temporarily orphaned if (method->mLineInfo == NULL) continue; @@ -5014,35 +5056,154 @@ void DbgModule::HotReplaceType(DbgType* newType) primaryType->mHotReplacedMethodList.PushFront(method); mHotPrimaryTypes.Add(primaryType); } - + + Dictionary 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; while (!newType->mMethodList.IsEmpty()) { DbgSubprogram* newMethod = newType->mMethodList.PopFront(); if (!newMethod->mBlock.IsEmpty()) { - newMethod->PopulateSubprogram(); + newMethod->PopulateSubprogram(); - bool found = false; - for (auto oldMethod : primaryType->mHotReplacedMethodList) + auto symInfo = mDebugTarget->mSymbolMap.Get(newMethod->mBlock.mLowPC); + if (symInfo != NULL) { - if (oldMethod->mBlock.IsEmpty()) - continue; - if (oldMethod->Equals(newMethod)) + DbgSubprogram* oldMethod = NULL; + if (oldProgramMap.TryGetValue(symInfo->mName, &oldMethod)) { - if (!setHotJumpFailed) + bool doHotJump = false; + + if (oldMethod->Equals(newMethod)) { - if (!mDebugger->SetHotJump(oldMethod, newMethod)) - setHotJumpFailed = true; - oldMethod->mWasHotReplaced = true; - } + doHotJump = 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; 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->mNeedsGlobalsPopulated = newType->mNeedsGlobalsPopulated; diff --git a/IDEHelper/DbgModule.h b/IDEHelper/DbgModule.h index fffe4ffc..a1170c91 100644 --- a/IDEHelper/DbgModule.h +++ b/IDEHelper/DbgModule.h @@ -358,6 +358,14 @@ public: }; #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* mLinkName; int mTemplateNameIdx; @@ -376,8 +384,7 @@ public: bool mVirtual; bool mHasThis; bool mNeedLineDataFixup; - bool mWasHotReplaced; - bool mWasModuleHotReplaced; // Module was hot replaced but a new version of the subprogram wasn't found + HotReplaceKind mHotReplaceKind; bool mIsOptimized; bool mHasLineAddrGaps; // There are gaps of addresses which are not covered by lineinfo DbgLineInfo* mLineInfo; @@ -397,8 +404,7 @@ public: mLinkName = NULL; mHasThis = false; mNeedLineDataFixup = true; - mWasHotReplaced = false; - mWasModuleHotReplaced = false; + mHotReplaceKind = HotReplaceKind_None; mHasLineAddrGaps = false; mPrologueSize = -1; mParentType = NULL; @@ -427,6 +433,7 @@ public: String GetParamName(int paramIdx); bool IsGenericMethod(); bool ThisIsSplat(); + bool IsLambda(); DbgSubprogram* GetRootInlineParent() { @@ -1201,6 +1208,7 @@ public: virtual String GetOldSourceCommand(const StringImpl& path) { return ""; } virtual bool DbgIsStrMutable(const char* str) { return true; } // Always assume its a copy virtual addr_target LocateSymbol(const StringImpl& name) { return 0; } + virtual DbgSubprogram* FindSubprogram(DbgType* dbgType, const char* methodName); void Fail(const StringImpl& error); void FindTemplateStr(const char*& name, int& templateNameIdx); diff --git a/IDEHelper/HotScanner.cpp b/IDEHelper/HotScanner.cpp index e2177358..c9c850e0 100644 --- a/IDEHelper/HotScanner.cpp +++ b/IDEHelper/HotScanner.cpp @@ -128,7 +128,7 @@ void DbgHotScanner::PopulateHotCallstacks() { auto subProgram = stackFrame->mSubProgram; - if (subProgram->mWasHotReplaced) + if (subProgram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) subProgram = mDebugger->TryFollowHotJump(subProgram, stackFrame->mRegisters.GetPC()); AddSubProgram(subProgram, false, ""); diff --git a/IDEHelper/Linker/BlCodeView.cpp b/IDEHelper/Linker/BlCodeView.cpp index ff3ba365..17e08396 100644 --- a/IDEHelper/Linker/BlCodeView.cpp +++ b/IDEHelper/Linker/BlCodeView.cpp @@ -2052,14 +2052,14 @@ void BlCodeView::CreateLinkerSymStream() ENVBLOCKSYM envBlock = { 0 }; envBlock.rectyp = S_ENVBLOCK; - str = "cwd"; str.Append(0); - str += cwd; str.Append(0); - str += "exe"; str.Append(0); - str += moduleFileName; str.Append(0); - str += "pdb"; str.Append(0); - str += mMsf.mFileName; str.Append(0); - str += "cmd"; str.Append(0); - str += GetCommandLineA(); str.Append(0); + str = "cwd"; str.Append('\0'); + str += cwd; str.Append('\0'); + str += "exe"; str.Append('\0'); + str += moduleFileName; str.Append('\0'); + str += "pdb"; str.Append('\0'); + str += mMsf.mFileName; str.Append('\0'); + str += "cmd"; str.Append('\0'); + str += GetCommandLineA(); str.Append('\0'); OUT_WITH_STR(ENVBLOCKSYM, envBlock, rgsz); for (auto segment : mContext->mSegments) diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 1d606c89..4a6d007f 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -1863,10 +1863,20 @@ bool WinDebugger::DoUpdate() bool isNonDebuggerBreak = false; if (wasDebugBreakpoint) - { + { // Go ahead and set EIP back one instruction BF_CONTEXT_IP(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 { @@ -2223,9 +2233,9 @@ bool WinDebugger::DoUpdate() } } else - { + { BfLogDbg("Ignoring break (old or ignored breakpoint)\n"); - mRunState = RunState_Running; + mRunState = RunState_Running; } } @@ -2363,7 +2373,7 @@ bool WinDebugger::DoUpdate() DbgSubprogram* dwSubprogram = NULL; 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"); mRunState = RunState_Running; @@ -2413,7 +2423,7 @@ bool WinDebugger::DoUpdate() } 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(); } @@ -2963,7 +2973,7 @@ void WinDebugger::CheckBreakpoint(WdBreakpoint* wdBreakpoint, DbgSrcFile* srcFil if ((foundInSequence) && (subProgram != lastFoundSubprogram)) 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 continue; @@ -2973,7 +2983,7 @@ void WinDebugger::CheckBreakpoint(WdBreakpoint* wdBreakpoint, DbgSrcFile* srcFil { 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 foundInSequence = true; @@ -4957,7 +4967,7 @@ bool WinDebugger::RollBackStackFrame(CPURegisters* registers, bool 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); BF_ASSERT(mDebugManager->mCritSect.mLockCount == 1); @@ -4968,14 +4978,14 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub if (jmpInstEnd > oldSubprogram->mBlock.mHighPC) { 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 - 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); return false; } - if (!oldSubprogram->mWasHotReplaced) + if (oldSubprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_Replaced) { for (int threadIdx = 0; threadIdx < (int)mThreadList.size(); threadIdx++) { @@ -5068,7 +5078,7 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub HotJumpOp jumpOp; 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); ::FlushInstructionCache(mProcessInfo.hProcess, (void*)(intptr)oldSubprogram->mBlock.mLowPC, sizeof(HotJumpOp)); return true; @@ -5076,7 +5086,7 @@ bool WinDebugger::SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSub DbgSubprogram* WinDebugger::TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr) { - if (!subprogram->mWasHotReplaced) + if (subprogram->mHotReplaceKind != DbgSubprogram::HotReplaceKind_Replaced) return subprogram; if (addr != subprogram->mBlock.mLowPC) @@ -10794,14 +10804,14 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o if (!dbgModule->mDisplayName.empty()) demangledName = dbgModule->mDisplayName + "!" + demangledName; - if (dwSubprogram->mWasHotReplaced) + if ((dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) || (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Invalid)) demangledName = "#" + demangledName; if (dbgModule->HasPendingDebugInfo()) *outFlags |= FrameFlags_HasPendingDebugInfo; if (dbgModule->CanGetOldSource()) *outFlags |= FrameFlags_CanGetOldSource; - if (dwSubprogram->mWasHotReplaced) + if ((dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Replaced) || (dwSubprogram->mHotReplaceKind == DbgSubprogram::HotReplaceKind_Invalid)) *outFlags |= FrameFlags_WasHotReplaced; if ((dwLineData != NULL) && (dwSrcFile != NULL)) diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index bcf53418..4fc8c9b5 100644 --- a/IDEHelper/WinDebugger.h +++ b/IDEHelper/WinDebugger.h @@ -479,7 +479,7 @@ public: bool PopulateRegisters(CPURegisters* registers, BF_CONTEXT& lcContext); virtual bool PopulateRegisters(CPURegisters* registers); 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); bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue());