Commit ff7c543a authored by hjk's avatar hjk

debugger: move RegisterHandler from DebuggerManager to DebuggerRunControl

parent 12fd2a60
......@@ -310,9 +310,9 @@ void CdbDebugEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::IT
void CdbDebugEnginePrivate::clearDisplay()
{
manager()->threadsHandler()->removeAll();
manager()->modulesHandler()->removeAll();
manager()->registerHandler()->removeAll();
m_engine->threadsHandler()->removeAll();
m_engine->modulesHandler()->removeAll();
m_engine->registerHandler()->removeAll();
}
void CdbDebugEnginePrivate::checkVersion()
......@@ -510,7 +510,7 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
}
// Clear any saved breakpoints and set initial breakpoints
m_engine->executeDebuggerCommand(QLatin1String("bc"));
if (manager()->breakHandler()->hasPendingBreakpoints()) {
if (m_engine->breakHandler()->hasPendingBreakpoints()) {
if (debugCDBExecution)
qDebug() << "processCreatedAttached: Syncing breakpoints";
m_engine->attemptBreakpointSynchronization();
......@@ -519,7 +519,7 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
// the exception to be delivered to the debugger
// Also, see special handling in slotModulesLoaded().
if (m_mode == AttachCrashedExternal) {
const QString crashParameter = manager()->runControl()->sp().crashParameter;
const QString crashParameter = m_engine->runControl()->sp().crashParameter;
if (!crashParameter.isEmpty()) {
ULONG64 evtNr = crashParameter.toULongLong();
const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
......@@ -1251,7 +1251,7 @@ void CdbDebugEngine::reloadRegisters()
const Registers registers = getRegisters(m_d->interfaces().debugControl, m_d->interfaces().debugRegisters, &errorMessage, intBase);
if (registers.isEmpty() && !errorMessage.isEmpty())
warning(msgFunctionFailed("reloadRegisters" , errorMessage));
manager()->registerHandler()->setRegisters(registers);
registerHandler()->setRegisters(registers);
}
void CdbDebugEngine::slotConsoleStubStarted()
......
......@@ -52,11 +52,8 @@
#include "watchwindow.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "stackhandler.h"
#include "stackframe.h"
#include "threadshandler.h"
#include "watchhandler.h"
......@@ -280,7 +277,6 @@ struct DebuggerManagerPrivate
// FIXME: Move to DebuggerRunControl
BreakHandler *m_breakHandler;
RegisterHandler *m_registerHandler;
SnapshotHandler *m_snapshotHandler;
StackHandler *m_stackHandler;
ThreadsHandler *m_threadsHandler;
......@@ -303,7 +299,7 @@ struct DebuggerManagerPrivate
QWidget *m_returnWindow;
QWidget *m_localsWindow;
QWidget *m_watchersWindow;
QWidget *m_registerWindow;
QAbstractItemView *m_registerWindow;
QAbstractItemView *m_modulesWindow;
QWidget *m_snapshotWindow;
SourceFilesWindow *m_sourceFilesWindow;
......@@ -358,7 +354,6 @@ DebuggerManager::~DebuggerManager()
doDelete(d->m_breakHandler);
doDelete(d->m_threadsHandler);
doDelete(d->m_registerHandler);
doDelete(d->m_snapshotHandler);
doDelete(d->m_stackHandler);
doDelete(d->m_watchHandler);
......@@ -377,8 +372,6 @@ void DebuggerManager::init()
d->m_state = DebuggerState(-1);
d->m_busy = false;
d->m_registerHandler = 0;
d->m_statusLabel = new QLabel;
d->m_statusLabel->setMinimumSize(QSize(30, 10));
......@@ -468,13 +461,6 @@ void DebuggerManager::init()
connect(sourceFilesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
// Registers
QAbstractItemView *registerView =
qobject_cast<QAbstractItemView *>(d->m_registerWindow);
d->m_registerHandler = new RegisterHandler;
registerView->setModel(d->m_registerHandler->model());
// Return Value
d->m_watchHandler = new WatchHandler(this);
QTreeView *returnView = qobject_cast<QTreeView *>(d->m_returnWindow);
......@@ -712,6 +698,11 @@ void DebuggerManager::clearCppCodeModelSnapshot()
d->m_codeModelSnapshot = CPlusPlus::Snapshot();
}
QAbstractItemView *DebuggerManager::registerWindow() const
{
return d->m_registerWindow;
}
QAbstractItemView *DebuggerManager::modulesWindow() const
{
return d->m_modulesWindow;
......@@ -833,7 +824,7 @@ void DebuggerManager::notifyInferiorPidChanged(qint64 pid)
void DebuggerManager::aboutToShutdown()
{
// TODO: STATE_DEBUG(d->m_engine);
STATE_DEBUG(d->m_engine);
if (d->m_engine)
d->m_engine->shutdown();
d->m_engine = 0;
......@@ -1088,7 +1079,6 @@ void DebuggerManager::cleanupViews()
stackHandler()->removeAll();
threadsHandler()->removeAll();
watchHandler()->cleanup();
registerHandler()->removeAll();
d->m_sourceFilesWindow->removeAll();
d->m_disassemblerViewAgent.cleanup();
d->m_actions.reverseDirectionAction->setChecked(false);
......@@ -1936,7 +1926,7 @@ void DebuggerManager::openTextEditor(const QString &titlePattern,
DebuggerRunControl *DebuggerManager::runControl() const
{
return const_cast<DebuggerRunControl *>(d->m_runControl);
return d->m_runControl;
}
DebuggerOutputWindow *DebuggerManager::debuggerOutputWindow() const
......@@ -1949,11 +1939,6 @@ BreakHandler *DebuggerManager::breakHandler() const
return d->m_breakHandler;
}
RegisterHandler *DebuggerManager::registerHandler() const
{
return d->m_registerHandler;
}
StackHandler *DebuggerManager::stackHandler() const
{
return d->m_stackHandler;
......@@ -1974,53 +1959,6 @@ SnapshotHandler *DebuggerManager::snapshotHandler() const
return d->m_snapshotHandler;
}
//////////////////////////////////////////////////////////////////////
//
// AbstractDebuggerEngine
//
//////////////////////////////////////////////////////////////////////
/*
void IDebuggerEngine::showStatusMessage(const QString &msg, int timeout)
{
m_manager->showStatusMessage(msg, timeout);
}
*/
DebuggerState IDebuggerEngine::state() const
{
return m_manager->state();
}
void IDebuggerEngine::setState(DebuggerState state, bool forced)
{
m_manager->setState(state, forced);
}
bool IDebuggerEngine::debuggerActionsEnabled() const
{
return m_manager->debuggerActionsEnabled();
}
void IDebuggerEngine::showModuleSymbols
(const QString &moduleName, const Symbols &symbols)
{
QTreeWidget *w = new QTreeWidget;
w->setColumnCount(3);
w->setRootIsDecorated(false);
w->setAlternatingRowColors(true);
w->setSortingEnabled(true);
w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
foreach (const Symbol &s, symbols) {
QTreeWidgetItem *it = new QTreeWidgetItem;
it->setData(0, Qt::DisplayRole, s.name);
it->setData(1, Qt::DisplayRole, s.address);
it->setData(2, Qt::DisplayRole, s.state);
w->addTopLevelItem(it);
}
manager()->createNewDock(w);
}
//////////////////////////////////////////////////////////////////////
//
// Testing
......
......@@ -255,16 +255,17 @@ public slots: // FIXME
friend class DebuggerRunControl;
public:
Internal::BreakHandler *breakHandler() const;
Internal::RegisterHandler *registerHandler() const;
Internal::StackHandler *stackHandler() const;
Internal::ThreadsHandler *threadsHandler() const;
Internal::WatchHandler *watchHandler() const;
Internal::SnapshotHandler *snapshotHandler() const;
Internal::DebuggerOutputWindow *debuggerOutputWindow() const;
private:
Internal::SourceFilesWindow *sourceFileWindow() const;
QAbstractItemView *modulesWindow() const;
QAbstractItemView *registerWindow() const;
QWidget *threadsWindow() const;
Internal::DebuggerManagerActions debuggerManagerActions() const;
......
......@@ -32,7 +32,15 @@
#include "debuggeroutputwindow.h"
#include "idebuggerengine.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "stackhandler.h"
#include "stackframe.h"
#include "threadshandler.h"
#include "watchhandler.h"
#include <projectexplorer/debugginghelper.h>
#include <projectexplorer/environment.h>
......@@ -51,6 +59,7 @@
#include <QtGui/QAbstractItemView>
#include <QtGui/QTextDocument>
#include <QtGui/QTreeWidget>
using namespace ProjectExplorer;
using namespace Debugger::Internal;
......@@ -159,10 +168,10 @@ public:
bool m_running;
ModulesHandler *m_modulesHandler;
RegisterHandler *m_registerHandler;
/*
// FIXME: Move from DebuggerManager
BreakHandler *m_breakHandler;
RegisterHandler *m_registerHandler;
SnapshotHandler *m_snapshotHandler;
StackHandler *m_stackHandler;
ThreadsHandler *m_threadsHandler;
......@@ -180,12 +189,14 @@ DebuggerRunControl::Private::Private(DebuggerRunControl *parent,
{
m_running = false;
m_modulesHandler = new ModulesHandler(q);
m_registerHandler = new RegisterHandler();
}
DebuggerRunControl::Private::~Private()
{
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(m_modulesHandler);
doDelete(m_registerHandler);
#undef doDelete
}
......@@ -326,7 +337,7 @@ BreakHandler *DebuggerRunControl::breakHandler() const
RegisterHandler *DebuggerRunControl::registerHandler() const
{
return d->m_manager->registerHandler();
return d->m_registerHandler;
}
StackHandler *DebuggerRunControl::stackHandler() const
......@@ -365,7 +376,92 @@ void DebuggerRunControl::startDebugger(IDebuggerEngine *engine)
d->m_engine = engine;
d->m_engine->setRunControl(this);
d->m_manager->modulesWindow()->setModel(d->m_modulesHandler->model());
d->m_manager->registerWindow()->setModel(d->m_registerHandler->model());
d->m_engine->startDebugger();
}
//////////////////////////////////////////////////////////////////////
//
// AbstractDebuggerEngine
//
//////////////////////////////////////////////////////////////////////
/*
void IDebuggerEngine::showStatusMessage(const QString &msg, int timeout)
{
m_manager->showStatusMessage(msg, timeout);
}
*/
DebuggerState IDebuggerEngine::state() const
{
return m_manager->state();
}
void IDebuggerEngine::setState(DebuggerState state, bool forced)
{
m_manager->setState(state, forced);
}
bool IDebuggerEngine::debuggerActionsEnabled() const
{
return m_manager->debuggerActionsEnabled();
}
void IDebuggerEngine::showModuleSymbols
(const QString &moduleName, const Symbols &symbols)
{
QTreeWidget *w = new QTreeWidget;
w->setColumnCount(3);
w->setRootIsDecorated(false);
w->setAlternatingRowColors(true);
w->setSortingEnabled(true);
w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
foreach (const Symbol &s, symbols) {
QTreeWidgetItem *it = new QTreeWidgetItem;
it->setData(0, Qt::DisplayRole, s.name);
it->setData(1, Qt::DisplayRole, s.address);
it->setData(2, Qt::DisplayRole, s.state);
w->addTopLevelItem(it);
}
manager()->createNewDock(w);
}
ModulesHandler *IDebuggerEngine::modulesHandler() const
{
return runControl()->modulesHandler();
}
BreakHandler *IDebuggerEngine::breakHandler() const
{
return runControl()->breakHandler();
}
RegisterHandler *IDebuggerEngine::registerHandler() const
{
return runControl()->registerHandler();
}
StackHandler *IDebuggerEngine::stackHandler() const
{
return runControl()->stackHandler();
}
ThreadsHandler *IDebuggerEngine::threadsHandler() const
{
return runControl()->threadsHandler();
}
WatchHandler *IDebuggerEngine::watchHandler() const
{
return runControl()->watchHandler();
}
SnapshotHandler *IDebuggerEngine::snapshotHandler() const
{
return runControl()->snapshotHandler();
}
} // namespace Debugger
......@@ -488,10 +488,9 @@ void GdbEngine::handleResponse(const QByteArray &buff)
// line="1584",shlib="/../libFoo_debug.dylib",times="0"}
const GdbMi bkpt = result.findChild("bkpt");
const int number = bkpt.findChild("number").data().toInt();
BreakHandler *handler = manager()->breakHandler();
BreakpointData *data = handler->findBreakpointByNumber(number);
BreakpointData *data = breakHandler()->findBreakpointByNumber(number);
setBreakpointDataFromOutput(data, bkpt);
handler->updateMarkers();
breakHandler()->updateMarkers();
} else {
qDebug() << "IGNORED ASYNC OUTPUT"
<< asyncClass << result.toString();
......@@ -876,7 +875,7 @@ void GdbEngine::commandTimeout()
if (mb->exec() == QMessageBox::Ok) {
showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
// This is an undefined state, so we just pull the emergency brake.
manager()->watchHandler()->endCycle();
watchHandler()->endCycle();
gdbProc()->kill();
} else {
showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
......@@ -972,7 +971,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
GdbResultDone)) {
#ifdef Q_OS_WIN
// Ignore spurious 'running' responses to 'attach'
const bool warning = !(manager()->runControl()->sp().startMode == AttachExternal
const bool warning = !(runControl()->sp().startMode == AttachExternal
&& cmd.command.startsWith("attach"));
#else
const bool warning = true;
......@@ -1399,8 +1398,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
} else {
// Older gdb versions do not produce "library loaded" messages
// so the breakpoint update is not triggered.
if (m_gdbVersion < 70000 && !m_isMacGdb
&& manager()->breakHandler()->size() > 0)
if (m_gdbVersion < 70000 && !m_isMacGdb && breakHandler()->size() > 0)
reloadBreakListInternal();
}
......@@ -1467,7 +1465,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
//
// Stack
//
manager()->stackHandler()->setCurrentIndex(0);
stackHandler()->setCurrentIndex(0);
updateLocals(qVariantFromValue(frame)); // Quick shot
reloadStack(false);
......@@ -1713,7 +1711,7 @@ void GdbEngine::abortDebugger() // called from the manager
int GdbEngine::currentFrame() const
{
return manager()->stackHandler()->currentIndex();
return stackHandler()->currentIndex();
}
static inline QString msgNoBinaryForToolChain(int tc)
......@@ -1838,9 +1836,8 @@ void GdbEngine::executeStep()
setTokenBarrier();
setState(InferiorRunningRequested);
showStatusMessage(tr("Step requested..."), 5000);
StackHandler *stackHandler = manager()->stackHandler();
if (m_gdbAdapter->isTrkAdapter() && stackHandler->stackSize() > 0)
postCommand("sal step," + stackHandler->topAddress().toLatin1());
if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0)
postCommand("sal step," + stackHandler()->topAddress().toLatin1());
if (manager()->isReverseDebugging())
postCommand("reverse-step", RunRequest, CB(handleExecuteStep));
else
......@@ -1902,9 +1899,8 @@ void GdbEngine::executeNext()
setTokenBarrier();
setState(InferiorRunningRequested);
showStatusMessage(tr("Step next requested..."), 5000);
StackHandler *stackHandler = manager()->stackHandler();
if (m_gdbAdapter->isTrkAdapter() && stackHandler->stackSize() > 0)
postCommand("sal next," + stackHandler->topAddress().toLatin1());
if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0)
postCommand("sal next," + stackHandler()->topAddress().toLatin1());
if (manager()->isReverseDebugging())
postCommand("reverse-next", RunRequest, CB(handleExecuteNext));
else
......@@ -2159,7 +2155,7 @@ QByteArray GdbEngine::breakpointLocation(const BreakpointData *data)
void GdbEngine::sendInsertBreakpoint(int index)
{
const BreakpointData *data = manager()->breakHandler()->at(index);
const BreakpointData *data = breakHandler()->at(index);
// Set up fallback in case of pending breakpoints which aren't handled
// by the MI interface.
if (data->type == BreakpointData::WatchpointType) {
......@@ -2200,9 +2196,9 @@ void GdbEngine::handleWatchInsert(const GdbResponse &response)
QByteArray ba = response.data.findChild("consolestreamoutput").data();
if (ba.startsWith("Hardware watchpoint ")) {
const int pos = ba.indexOf(':', 20);
BreakpointData *data = manager()->breakHandler()->at(index);
BreakpointData *data = breakHandler()->at(index);
data->bpNumber = ba.mid(20, pos - 20);
manager()->breakHandler()->updateMarkers();
breakHandler()->updateMarkers();
} else {
showMessage(_("CANNOT PARSE WATCHPOINT FROM" + ba));
}
......@@ -2212,7 +2208,7 @@ void GdbEngine::handleWatchInsert(const GdbResponse &response)
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{
int index = response.cookie.toInt();
BreakpointData *data = manager()->breakHandler()->at(index);
BreakpointData *data = breakHandler()->at(index);
if (response.resultClass == GdbResultDone) {
// Interesting only on Mac?
GdbMi bkpt = response.data.findChild("bkpt");
......@@ -2285,11 +2281,10 @@ void GdbEngine::handleBreakList(const GdbMi &table)
//qDebug() << "LEFT" << bkpts.size() << "BREAKPOINTS";
}
BreakHandler *handler = manager()->breakHandler();
foreach (const GdbMi &bkpt, bkpts) {
BreakpointData temp;
setBreakpointDataFromOutput(&temp, bkpt);
BreakpointData *data = handler->findSimilarBreakpoint(temp);
BreakpointData *data = breakHandler()->findSimilarBreakpoint(temp);
//qDebug() << "\n\nGOT: " << bkpt.toString() << '\n' << temp.toString();
if (data) {
//qDebug() << " FROM: " << data->toString();
......@@ -2306,9 +2301,8 @@ void GdbEngine::handleBreakList(const GdbMi &table)
void GdbEngine::handleBreakDisable(const GdbResponse &response)
{
BreakHandler *handler = manager()->breakHandler();
if (response.resultClass == GdbResultDone) {
handler->updateMarkers();
breakHandler()->updateMarkers();
}
}
......@@ -2325,8 +2319,7 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response)
// 29^done
//
// gdb 6.3 does not produce any console output
BreakHandler *handler = manager()->breakHandler();
BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
BreakpointData *data = breakHandler()->findBreakpointByNumber(bpNumber);
if (response.resultClass == GdbResultDone && data) {
QString msg = _(response.data.findChild("consolestreamoutput").data());
//if (msg.contains(__("Will stop next time breakpoint"))) {
......@@ -2336,15 +2329,14 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response)
//}
// FIXME: this assumes it is doing the right thing...
data->bpIgnoreCount = data->ignoreCount;
handler->updateMarkers();
breakHandler()->updateMarkers();
}
}
void GdbEngine::handleBreakCondition(const GdbResponse &response)
{
int bpNumber = response.cookie.toInt();
BreakHandler *handler = manager()->breakHandler();
BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
BreakpointData *data = breakHandler()->findBreakpointByNumber(bpNumber);
if (response.resultClass == GdbResultDone) {
// We just assume it was successful. Otherwise we had to parse
// the output stream data.
......@@ -2359,7 +2351,7 @@ void GdbEngine::handleBreakCondition(const GdbResponse &response)
data->bpCondition = data->condition;
}
}
handler->updateMarkers();
breakHandler()->updateMarkers();
}
void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointData *data)
......@@ -2426,8 +2418,7 @@ void GdbEngine::handleBreakInfo(const GdbResponse &response)
// Old-style output for multiple breakpoints, presumably in a
// constructor.
const int bpNumber = response.cookie.toInt();
const BreakHandler *handler = manager()->breakHandler();
BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
BreakpointData *data = breakHandler()->findBreakpointByNumber(bpNumber);
if (data) {
QString str = QString::fromLocal8Bit(
response.data.findChild("consolestreamoutput").data());
......@@ -2443,8 +2434,7 @@ void GdbEngine::handleInfoLine(const GdbResponse &response)
// at address 0x80526aa <_Z10...+131> and ends at 0x80526b5
// <_Z10testQStackv+142>.\n"
const int bpNumber = response.cookie.toInt();
const BreakHandler *handler = manager()->breakHandler();
BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
BreakpointData *data = breakHandler()->findBreakpointByNumber(bpNumber);
if (!data)
return;
QByteArray ba = response.data.findChild("consolestreamoutput").data();
......@@ -2506,7 +2496,7 @@ void GdbEngine::attemptBreakpointSynchronization()
return;
}
BreakHandler *handler = manager()->breakHandler();
BreakHandler *handler = breakHandler();
foreach (BreakpointData *data, handler->takeDisabledBreakpoints()) {
QByteArray bpNumber = data->bpNumber;
......@@ -2753,10 +2743,8 @@ void GdbEngine::reloadSourceFilesInternal()
void GdbEngine::selectThread(int index)
{
ThreadsHandler *threadsHandler = manager()->threadsHandler();
threadsHandler->setCurrentThread(index);
QList<ThreadData> threads = threadsHandler->threads();
threadsHandler()->setCurrentThread(index);
QList<ThreadData> threads = threadsHandler()->threads();
QTC_ASSERT(index < threads.size(), return);
int id = threads.at(index).id;
showStatusMessage(tr("Retrieving data for stack view..."), 10000);
......@@ -2871,7 +2859,7 @@ void GdbEngine::handleStackListFrames(const GdbResponse &response)
bool canExpand = !cookie.isFull
&& (n >= theDebuggerAction(MaximalStackDepth)->value().toInt());
theDebuggerAction(ExpandStack)->setEnabled(canExpand);
manager()->stackHandler()->setFrames(stackFrames, canExpand);
stackHandler()->setFrames(stackFrames, canExpand);
// We can't jump to any file if we don't have any frames.
if (stackFrames.isEmpty())
......@@ -2895,7 +2883,7 @@ void GdbEngine::handleStackListFrames(const GdbResponse &response)
// when reading the *stopped message.
bool jump = (m_isMacGdb || targetFrame != 0);
manager()->stackHandler()->setCurrentIndex(targetFrame);
stackHandler()->setCurrentIndex(targetFrame);
if (jump || cookie.gotoLocation)
activateFrame(targetFrame);
}
......@@ -2906,25 +2894,25 @@ void GdbEngine::activateFrame(int frameIndex)
if (state() != InferiorStopped && state() != InferiorUnrunnable)
return;
StackHandler *stackHandler = manager()->stackHandler();
int oldIndex = stackHandler->currentIndex();
StackHandler *handler = stackHandler();
int oldIndex = handler->currentIndex();
if (frameIndex == stackHandler->stackSize()) {
if (frameIndex == handler->stackSize()) {
reloadFullStack();
return;
}
QTC_ASSERT(frameIndex < stackHandler->stackSize(), return);
QTC_ASSERT(frameIndex < handler->stackSize(), return);