aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2014-02-05 14:38:03 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-05 16:14:56 +0100
commit4dfe58d27ced74c0e28c1764ac036d7ec27f14c9 (patch)
treea18f06e009fea392bf7fd960f1cf4bce01fcd46b
parent1cf089f9d436715955d6eb267ff609d7fafad78c (diff)
Add a special Debug instruction to the interpreter and use it
This avoid having to check for the debugger at every instruction we execute. Instead we only add debug instructions at the beginning of every line and every basic block when we have a debugger. This still allows interrupting the JS execution at any time (as we can't loop inside a basic block), and single stepping through lines. But it has no overhead when the debugger is not running and a lot less when it is running. Change-Id: Ib17170b42944b608fc6caa1891082205dd2b2763 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h12
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp18
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp7
4 files changed, 33 insertions, 12 deletions
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 293452cf47..bd8fc2301d 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
+ F(Debug, debug) \
F(LoadRuntimeString, loadRuntimeString) \
F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
@@ -142,11 +143,9 @@ QT_BEGIN_NAMESPACE
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QQmlJS::Moth::Instr) - 1)
#ifdef MOTH_THREADED_INTERPRETER
-# define MOTH_INSTR_HEADER void *code; \
- unsigned int breakPoint : 1;
+# define MOTH_INSTR_HEADER void *code;
#else
-# define MOTH_INSTR_HEADER quint8 instructionType; \
- unsigned int breakPoint : 1;
+# define MOTH_INSTR_HEADER quint32 instructionType;
#endif
#define MOTH_INSTR_ENUM(I, FMT) I,
@@ -234,6 +233,10 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_debug {
+ MOTH_INSTR_HEADER
+ quint32 breakPoint;
+ };
struct instr_loadRuntimeString {
MOTH_INSTR_HEADER
int stringId;
@@ -703,6 +706,7 @@ union Instr
instr_common common;
instr_ret ret;
+ instr_debug debug;
instr_loadRuntimeString loadRuntimeString;
instr_loadRegExp loadRegExp;
instr_move move;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index c8f15ae0b7..fd7e998ac4 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -47,6 +47,7 @@
#include <private/qv4function_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qqmlengine_p.h>
#undef USE_TYPE_INFO
@@ -217,7 +218,13 @@ void InstructionSelection::run(int functionIndex)
QVector<uint> lineNumberMappings;
lineNumberMappings.reserve(_function->basicBlocks.size() * 2);
+ uint currentLine = -1;
for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ if (irModule->debugMode) {
+ Instruction::Debug debug;
+ debug.breakPoint = 0;
+ addInstruction(debug);
+ }
_block = _function->basicBlocks[i];
_nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
@@ -237,8 +244,15 @@ void InstructionSelection::run(int functionIndex)
foreach (V4IR::Stmt *s, _block->statements) {
_currentStatement = s;
- if (s->location.isValid())
+ if (s->location.isValid()) {
lineNumberMappings << _codeNext - _codeStart << s->location.startLine;
+ if (irModule->debugMode && s->location.startLine != currentLine) {
+ Instruction::Debug debug;
+ debug.breakPoint = 0;
+ addInstruction(debug);
+ currentLine = s->location.startLine;
+ }
+ }
s->accept(this);
}
@@ -1142,12 +1156,12 @@ void QQmlJS::Moth::InstructionSelection::callBuiltinConvertThisToObject()
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
{
+
#ifdef MOTH_THREADED_INTERPRETER
instr.common.code = VME::instructionJumpTable()[static_cast<int>(type)];
#else
instr.common.instructionType = type;
#endif
- instr.common.breakPoint = 0;
int instructionSize = Instr::size(type);
if (_codeEnd - _codeNext < instructionSize) {
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 4170b6817f..32d8c1fc4a 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -648,15 +648,15 @@ void Debugger::applyPendingBreakPoints()
void Debugger::setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff)
{
uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
- QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
- instruction->common.breakPoint = onoff;
+ QQmlJS::Moth::Instr::instr_debug *debug = reinterpret_cast<QQmlJS::Moth::Instr::instr_debug *>(codePtr);
+ debug->breakPoint = onoff;
}
bool Debugger::hasBreakOnInstruction(Function *function, qptrdiff codeOffset)
{
uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
- QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
- return instruction->common.breakPoint;
+ QQmlJS::Moth::Instr::instr_debug *debug = reinterpret_cast<QQmlJS::Moth::Instr::instr_debug *>(codePtr);
+ return debug->breakPoint;
}
bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 45d8098034..22fe4968a2 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -64,8 +64,6 @@ using namespace QQmlJS::Moth;
#define MOTH_BEGIN_INSTR_COMMON(I) { \
const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \
code += InstrMeta<(int)Instr::I>::Size; \
- if (debugger && (instr.breakPoint || debugger->pauseAtNextOpportunity())) \
- debugger->maybeBreakAtInstruction(code, instr.breakPoint); \
Q_UNUSED(instr); \
TRACE_INSTR(I)
@@ -659,6 +657,11 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
return VALUE(instr.result).asReturnedValue();
MOTH_END_INSTR(Ret)
+ MOTH_BEGIN_INSTR(Debug)
+ if (debugger && (instr.breakPoint || debugger->pauseAtNextOpportunity()))
+ debugger->maybeBreakAtInstruction(code, instr.breakPoint);
+ MOTH_END_INSTR(Debug)
+
MOTH_BEGIN_INSTR(LoadThis)
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)