forked from qt-creator/qt-creator
Debugger: Simplify removal of outdated L&E items
This removes the need of bookkeeping on the engine side. It's basically a kind of mark-and-sweep: On update begin mark items that are expected to change as outdated, while data arrives, undo that marking, and update end remove all remaining marked items. Change-Id: I739b84869033d511d5c9a80605c079e87ef4f6a7 Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
@@ -1340,7 +1340,7 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
watchHandler()->notifyUpdateStarted();
|
watchHandler()->notifyUpdateStarted(updateParameters.partialVariables());
|
||||||
|
|
||||||
/* Watchers: Forcibly discard old symbol group as switching from
|
/* Watchers: Forcibly discard old symbol group as switching from
|
||||||
* thread 0/frame 0 -> thread 1/assembly -> thread 0/frame 0 will otherwise re-use it
|
* thread 0/frame 0 -> thread 1/assembly -> thread 0/frame 0 will otherwise re-use it
|
||||||
@@ -1775,7 +1775,6 @@ void CdbEngine::handleRegistersExt(const CdbResponse &response)
|
|||||||
|
|
||||||
void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate)
|
void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate)
|
||||||
{
|
{
|
||||||
watchHandler()->notifyUpdateFinished();
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
if (boolSetting(VerboseLog))
|
if (boolSetting(VerboseLog))
|
||||||
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.extensionReply), LogDebug);
|
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.extensionReply), LogDebug);
|
||||||
@@ -1796,6 +1795,7 @@ void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate)
|
|||||||
} else {
|
} else {
|
||||||
showMessage(QString::fromLatin1(response.errorMessage), LogWarning);
|
showMessage(QString::fromLatin1(response.errorMessage), LogWarning);
|
||||||
}
|
}
|
||||||
|
watchHandler()->notifyUpdateFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbEngine::handleExpandLocals(const CdbResponse &response)
|
void CdbEngine::handleExpandLocals(const CdbResponse &response)
|
||||||
|
|||||||
@@ -1944,12 +1944,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QByteArray> toDelete;
|
|
||||||
if (!partial) {
|
|
||||||
foreach (WatchItem *item, handler->model()->itemsAtLevel<WatchItem *>(2))
|
|
||||||
toDelete.insert(item->iname);
|
|
||||||
}
|
|
||||||
|
|
||||||
GdbMi data = all["data"];
|
GdbMi data = all["data"];
|
||||||
foreach (const GdbMi &child, data.children()) {
|
foreach (const GdbMi &child, data.children()) {
|
||||||
WatchItem *item = new WatchItem(child);
|
WatchItem *item = new WatchItem(child);
|
||||||
@@ -1958,7 +1952,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
|||||||
item->size = ti.size;
|
item->size = ti.size;
|
||||||
|
|
||||||
handler->insertItem(item);
|
handler->insertItem(item);
|
||||||
toDelete.remove(item->iname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GdbMi ns = all["qtnamespace"];
|
GdbMi ns = all["qtnamespace"];
|
||||||
@@ -1967,8 +1960,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
|||||||
showMessage(_("FOUND NAMESPACED QT: " + ns.data()));
|
showMessage(_("FOUND NAMESPACED QT: " + ns.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->purgeOutdatedItems(toDelete);
|
|
||||||
|
|
||||||
static int count = 0;
|
static int count = 0;
|
||||||
showMessage(_("<Rebuild Watchmodel %1 @ %2 >")
|
showMessage(_("<Rebuild Watchmodel %1 @ %2 >")
|
||||||
.arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
|
.arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
|
||||||
|
|||||||
@@ -120,6 +120,14 @@ class UpdateParameters
|
|||||||
public:
|
public:
|
||||||
UpdateParameters() {}
|
UpdateParameters() {}
|
||||||
|
|
||||||
|
QList<QByteArray> partialVariables() const
|
||||||
|
{
|
||||||
|
QList<QByteArray> result;
|
||||||
|
if (!partialVariable.isEmpty())
|
||||||
|
result.append(partialVariable);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray partialVariable;
|
QByteArray partialVariable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4660,7 +4660,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
{
|
{
|
||||||
m_pendingBreakpointRequests = 0;
|
m_pendingBreakpointRequests = 0;
|
||||||
|
|
||||||
watchHandler()->notifyUpdateStarted();
|
watchHandler()->notifyUpdateStarted(params.partialVariables());
|
||||||
|
|
||||||
DebuggerCommand cmd("showData");
|
DebuggerCommand cmd("showData");
|
||||||
watchHandler()->appendFormatRequests(&cmd);
|
watchHandler()->appendFormatRequests(&cmd);
|
||||||
@@ -4716,7 +4716,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
|
|
||||||
void GdbEngine::handleStackFrame(const DebuggerResponse &response)
|
void GdbEngine::handleStackFrame(const DebuggerResponse &response)
|
||||||
{
|
{
|
||||||
watchHandler()->notifyUpdateFinished();
|
|
||||||
if (response.resultClass == ResultDone) {
|
if (response.resultClass == ResultDone) {
|
||||||
QByteArray out = response.consoleStreamOutput;
|
QByteArray out = response.consoleStreamOutput;
|
||||||
while (out.endsWith(' ') || out.endsWith('\n'))
|
while (out.endsWith(' ') || out.endsWith('\n'))
|
||||||
@@ -4735,6 +4734,7 @@ void GdbEngine::handleStackFrame(const DebuggerResponse &response)
|
|||||||
} else {
|
} else {
|
||||||
showMessage(_("DUMPER FAILED: " + response.toString()));
|
showMessage(_("DUMPER FAILED: " + response.toString()));
|
||||||
}
|
}
|
||||||
|
watchHandler()->notifyUpdateFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
|
QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
|
||||||
|
|||||||
@@ -447,8 +447,8 @@ void LldbEngine::handleResponse(const QByteArray &response)
|
|||||||
foreach (const GdbMi &item, all.children()) {
|
foreach (const GdbMi &item, all.children()) {
|
||||||
const QByteArray name = item.name();
|
const QByteArray name = item.name();
|
||||||
if (name == "all") {
|
if (name == "all") {
|
||||||
watchHandler()->notifyUpdateFinished();
|
|
||||||
updateLocalsView(item);
|
updateLocalsView(item);
|
||||||
|
watchHandler()->notifyUpdateFinished();
|
||||||
} else if (name == "dumpers") {
|
} else if (name == "dumpers") {
|
||||||
watchHandler()->addDumpers(item);
|
watchHandler()->addDumpers(item);
|
||||||
setupInferiorStage2();
|
setupInferiorStage2();
|
||||||
@@ -864,7 +864,7 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
watchHandler()->notifyUpdateStarted();
|
watchHandler()->notifyUpdateStarted(params.partialVariables());
|
||||||
|
|
||||||
DebuggerCommand cmd("updateData");
|
DebuggerCommand cmd("updateData");
|
||||||
cmd.arg("nativeMixed", isNativeMixedActive());
|
cmd.arg("nativeMixed", isNativeMixedActive());
|
||||||
|
|||||||
@@ -572,17 +572,10 @@ void PdbEngine::refreshLocals(const GdbMi &vars)
|
|||||||
WatchHandler *handler = watchHandler();
|
WatchHandler *handler = watchHandler();
|
||||||
handler->resetValueCache();
|
handler->resetValueCache();
|
||||||
|
|
||||||
QSet<QByteArray> toDelete;
|
foreach (const GdbMi &child, vars.children())
|
||||||
foreach (WatchItem *item, handler->model()->itemsAtLevel<WatchItem *>(2))
|
handler->insertItem(new WatchItem(child));
|
||||||
toDelete.insert(item->iname);
|
|
||||||
|
|
||||||
foreach (const GdbMi &child, vars.children()) {
|
handler->notifyUpdateFinished();
|
||||||
WatchItem *item = new WatchItem(child);
|
|
||||||
handler->insertItem(item);
|
|
||||||
toDelete.remove(item->iname);
|
|
||||||
}
|
|
||||||
|
|
||||||
handler->purgeOutdatedItems(toDelete);
|
|
||||||
|
|
||||||
DebuggerToolTipManager::updateEngine(this);
|
DebuggerToolTipManager::updateEngine(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ WatchData::WatchData() :
|
|||||||
elided(0),
|
elided(0),
|
||||||
wantsChildren(false),
|
wantsChildren(false),
|
||||||
valueEnabled(true),
|
valueEnabled(true),
|
||||||
valueEditable(true)
|
valueEditable(true),
|
||||||
|
outdated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ public:
|
|||||||
bool wantsChildren;
|
bool wantsChildren;
|
||||||
bool valueEnabled; // Value will be enabled or not
|
bool valueEnabled; // Value will be enabled or not
|
||||||
bool valueEditable; // Value will be editable
|
bool valueEditable; // Value will be editable
|
||||||
|
bool outdated; // \internal item is to be removed.
|
||||||
|
|
||||||
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1221,8 +1221,20 @@ void WatchHandler::resetWatchers()
|
|||||||
loadSessionData();
|
loadSessionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::notifyUpdateStarted()
|
void WatchHandler::notifyUpdateStarted(const QList<QByteArray> &inames)
|
||||||
{
|
{
|
||||||
|
auto marker = [](TreeItem *it) { static_cast<WatchItem *>(it)->outdated = true; };
|
||||||
|
|
||||||
|
if (inames.isEmpty()) {
|
||||||
|
foreach (auto item, m_model->itemsAtLevel<WatchItem *>(2))
|
||||||
|
item->walkTree(marker);
|
||||||
|
} else {
|
||||||
|
foreach (auto iname, inames) {
|
||||||
|
if (WatchItem *item = m_model->findItem(iname))
|
||||||
|
item->walkTree(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_model->m_requestUpdateTimer.start(80);
|
m_model->m_requestUpdateTimer.start(80);
|
||||||
m_model->m_contentsValid = false;
|
m_model->m_contentsValid = false;
|
||||||
updateWatchersWindow();
|
updateWatchersWindow();
|
||||||
@@ -1230,25 +1242,32 @@ void WatchHandler::notifyUpdateStarted()
|
|||||||
|
|
||||||
void WatchHandler::notifyUpdateFinished()
|
void WatchHandler::notifyUpdateFinished()
|
||||||
{
|
{
|
||||||
|
struct OutDatedItemsFinder : public TreeItemVisitor
|
||||||
|
{
|
||||||
|
bool preVisit(TreeItem *item)
|
||||||
|
{
|
||||||
|
auto watchItem = static_cast<WatchItem *>(item);
|
||||||
|
if (level() <= 1 || !watchItem->outdated)
|
||||||
|
return true;
|
||||||
|
toRemove.append(watchItem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<WatchItem *> toRemove;
|
||||||
|
} finder;
|
||||||
|
|
||||||
|
m_model->root()->walkTree(&finder);
|
||||||
|
|
||||||
|
foreach (auto item, finder.toRemove)
|
||||||
|
delete m_model->takeItem(item);
|
||||||
|
|
||||||
m_model->m_contentsValid = true;
|
m_model->m_contentsValid = true;
|
||||||
updateWatchersWindow();
|
updateWatchersWindow();
|
||||||
|
m_model->reexpandItems();
|
||||||
m_model->m_requestUpdateTimer.stop();
|
m_model->m_requestUpdateTimer.stop();
|
||||||
emit m_model->updateFinished();
|
emit m_model->updateFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::purgeOutdatedItems(const QSet<QByteArray> &inames)
|
|
||||||
{
|
|
||||||
foreach (const QByteArray &iname, inames) {
|
|
||||||
WatchItem *item = findItem(iname);
|
|
||||||
delete m_model->takeItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_model->layoutChanged();
|
|
||||||
m_model->reexpandItems();
|
|
||||||
m_model->m_contentsValid = true;
|
|
||||||
updateWatchersWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchHandler::removeItemByIName(const QByteArray &iname)
|
void WatchHandler::removeItemByIName(const QByteArray &iname)
|
||||||
{
|
{
|
||||||
WatchItem *item = m_model->findItem(iname);
|
WatchItem *item = m_model->findItem(iname);
|
||||||
|
|||||||
@@ -197,9 +197,9 @@ public:
|
|||||||
void removeAllData(bool includeInspectData = false);
|
void removeAllData(bool includeInspectData = false);
|
||||||
void resetValueCache();
|
void resetValueCache();
|
||||||
void resetWatchers();
|
void resetWatchers();
|
||||||
void notifyUpdateStarted();
|
|
||||||
|
void notifyUpdateStarted(const QList<QByteArray> &inames = {});
|
||||||
void notifyUpdateFinished();
|
void notifyUpdateFinished();
|
||||||
void purgeOutdatedItems(const QSet<QByteArray> &inames);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WatchModel *m_model; // Owned.
|
WatchModel *m_model; // Owned.
|
||||||
|
|||||||
Reference in New Issue
Block a user