aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/v4/moth/qv4isel_moth_p.h1
-rw-r--r--src/qml/qml/v4/qv4codegen.cpp4
-rw-r--r--src/qml/qml/v4/qv4engine.cpp169
-rw-r--r--src/qml/qml/v4/qv4engine_p.h30
-rw-r--r--src/qml/qml/v4/qv4function.cpp21
-rw-r--r--src/qml/qml/v4/qv4function_p.h10
-rw-r--r--src/qml/qml/v4/qv4isel_masm.cpp22
-rw-r--r--src/qml/qml/v4/qv4isel_masm_p.h10
-rw-r--r--src/qml/qml/v4/qv4jsir.cpp17
-rw-r--r--src/qml/qml/v4/qv4jsir_p.h19
-rw-r--r--src/qml/qml/v4/qv4runtime.cpp45
-rw-r--r--src/qml/qml/v4/qv4runtime_p.h21
-rw-r--r--src/qml/qml/v4/qv4script_p.h4
-rw-r--r--src/qml/qml/v4/qv4unwindhelper.cpp2
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p-arm.h3
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p-dw2.h18
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p.h3
-rw-r--r--tools/v4/main.cpp38
18 files changed, 335 insertions, 102 deletions
diff --git a/src/qml/qml/v4/moth/qv4isel_moth_p.h b/src/qml/qml/v4/moth/qv4isel_moth_p.h
index c499b5d137..49cef5cef0 100644
--- a/src/qml/qml/v4/moth/qv4isel_moth_p.h
+++ b/src/qml/qml/v4/moth/qv4isel_moth_p.h
@@ -26,6 +26,7 @@ protected:
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
virtual void visitTry(V4IR::Try *);
+ virtual void visitDebugAnnotation(V4IR::DebugAnnotation *) {}
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
diff --git a/src/qml/qml/v4/qv4codegen.cpp b/src/qml/qml/v4/qv4codegen.cpp
index 0e4c24ec2c..31f7e5c45d 100644
--- a/src/qml/qml/v4/qv4codegen.cpp
+++ b/src/qml/qml/v4/qv4codegen.cpp
@@ -116,6 +116,7 @@ struct ComputeUseDef: V4IR::StmtVisitor, V4IR::ExprVisitor
if (! _stmt->d->defs.contains(t->exceptionVar->index))
_stmt->d->defs.append(t->exceptionVar->index);
}
+ virtual void visitDebugAnnotation(V4IR::DebugAnnotation *) {}
virtual void visitTemp(V4IR::Temp *e) {
if (e->index < 0 || e->scope != 0)
@@ -371,6 +372,7 @@ protected:
virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
virtual void visitTry(V4IR::Try *) {}
+ virtual void visitDebugAnnotation(V4IR::DebugAnnotation *) {}
virtual void visitCall(V4IR::Call *e) {
e->base->accept(this);
@@ -550,6 +552,7 @@ protected:
virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
virtual void visitTry(V4IR::Try *t) { visitTemp(t->exceptionVar); }
+ virtual void visitDebugAnnotation(V4IR::DebugAnnotation *) {}
virtual void visitTemp(V4IR::Temp *e) {
if (e->scope) // scoped local
@@ -1340,6 +1343,7 @@ void Codegen::accept(Node *node)
void Codegen::statement(Statement *ast)
{
+ _block->DEBUGANNOTATION(ast->firstSourceLocation());
accept(ast);
}
diff --git a/src/qml/qml/v4/qv4engine.cpp b/src/qml/qml/v4/qv4engine.cpp
index c84e24ef5c..81ac59c037 100644
--- a/src/qml/qml/v4/qv4engine.cpp
+++ b/src/qml/qml/v4/qv4engine.cpp
@@ -64,6 +64,10 @@
#include "qv4executableallocator_p.h"
#include "qv4sequenceobject_p.h"
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
+#include <execinfo.h>
+#endif
+
#ifdef V4_ENABLE_JIT
# include "qv4isel_masm_p.h"
#else // !V4_ENABLE_JIT
@@ -81,6 +85,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
, globalObject(0)
, globalCode(0)
, externalResourceComparison(0)
+ , functionsNeedSort(false)
, regExpCache(0)
{
MemoryManager::GCBlocker gcBlocker(memoryManager);
@@ -361,6 +366,7 @@ Function *ExecutionEngine::newFunction(const QString &name)
{
Function *f = new Function(newIdentifier(name));
functions.append(f);
+ functionsNeedSort = true;
return f;
}
@@ -551,23 +557,100 @@ Object *ExecutionEngine::qmlContextObject() const
return static_cast<CallContext *>(ctx)->activation;
}
+namespace {
+ struct NativeFrame {
+ Function *function;
+ int line;
+ };
+
+ struct NativeStackTrace
+ {
+ void *trace[100];
+ int nativeFrameCount;
+ int currentNativeFrame;
+ ExecutionEngine *engine;
+
+ NativeStackTrace(ExecutionContext *context)
+ {
+ engine = context->engine;
+ currentNativeFrame = 0;
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
+ UnwindHelper::prepareForUnwind(context);
+
+ nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
+#else
+ nativeFrameCount = 0;
+#endif
+ }
+
+ NativeFrame nextFrame() {
+ NativeFrame frame;
+ frame.function = 0;
+ frame.line = -1;
+
+ for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
+ quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
+ // The pointers from the back trace point to the return address, but we are interested in
+ // the caller site.
+ pc = pc - 1;
+
+ Function *f = engine->functionForProgramCounter(pc);
+ if (!f)
+ continue;
+
+ frame.function = f;
+ frame.line = f->lineNumberForProgramCounter(pc);
+ }
+
+ return frame;
+ }
+ };
+}
+
QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
{
+ NativeStackTrace nativeTrace(current);
+
QVector<StackFrame> stack;
QV4::ExecutionContext *c = current;
while (c && frameLimit) {
- if (CallContext *c = c->asCallContext()) {
+ if (CallContext *callCtx = c->asCallContext()) {
StackFrame frame;
- frame.source = c->function->function->sourceFile;
- frame.function = c->function->name->toQString();
+ if (callCtx->function->function)
+ frame.source = callCtx->function->function->sourceFile;
+ frame.function = callCtx->function->name->toQString();
frame.line = -1;
frame.column = -1;
+
+ if (callCtx->function->function) {
+ // Try to complete the line number information
+ NativeFrame nativeFrame = nativeTrace.nextFrame();
+ if (nativeFrame.function == callCtx->function->function)
+ frame.line = nativeFrame.line;
+ }
+
stack.append(frame);
--frameLimit;
}
c = c->parent;
}
+
+ if (frameLimit && globalCode) {
+ StackFrame frame;
+ frame.source = globalCode->sourceFile;
+ frame.function = globalCode->name->toQString();
+ frame.line = -1;
+ frame.column = -1;
+
+ // Try to complete the line number information
+ NativeFrame nativeFrame = nativeTrace.nextFrame();
+ if (nativeFrame.function == globalCode)
+ frame.line = nativeFrame.line;
+
+ stack.append(frame);
+ }
return stack;
}
@@ -577,15 +660,10 @@ ExecutionEngine::StackFrame ExecutionEngine::currentStackFrame() const
frame.line = -1;
frame.column = -1;
- QV4::ExecutionContext *c = current;
- while (c) {
- if (CallContext *callCtx = c->asCallContext()) {
- frame.source = callCtx->function->function->sourceFile;
- frame.function = callCtx->function->name->toQString();
- return frame;
- }
- c = c->parent;
- }
+ QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
+ if (!trace.isEmpty())
+ frame = trace.first();
+
return frame;
}
@@ -682,3 +760,70 @@ void ExecutionEngine::markObjects()
variantPrototype->mark();
sequencePrototype->mark();
}
+
+namespace {
+ bool functionSortHelper(Function *lhs, Function *rhs)
+ {
+ return reinterpret_cast<quintptr>(lhs->code) < reinterpret_cast<quintptr>(rhs->code);
+ }
+
+ struct FindHelper
+ {
+ bool operator()(Function *function, quintptr pc)
+ {
+ return reinterpret_cast<quintptr>(function->code) < pc
+ && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc;
+ }
+
+ bool operator()(quintptr pc, Function *function)
+ {
+ return pc < reinterpret_cast<quintptr>(function->code);
+ }
+ };
+}
+
+Function *ExecutionEngine::functionForProgramCounter(quintptr pc) const
+{
+ if (functionsNeedSort) {
+ qSort(functions.begin(), functions.end(), functionSortHelper);
+ functionsNeedSort = false;
+ }
+
+ QVector<Function*>::ConstIterator it = qBinaryFind(functions.constBegin(), functions.constEnd(),
+ pc, FindHelper());
+ if (it != functions.constEnd())
+ return *it;
+ return 0;
+}
+
+Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line)
+ : exception(exceptionValue)
+ , m_line(line)
+{
+ m_file = throwingContext->currentFileName();
+ this->throwingContext = throwingContext->engine->current;
+ accepted = false;
+ m_stackTrace = throwingContext->engine->stackTrace();
+}
+
+Exception::~Exception()
+{
+ assert(accepted);
+}
+
+void Exception::accept(ExecutionContext *catchingContext)
+{
+ assert(!accepted);
+ accepted = true;
+ partiallyUnwindContext(catchingContext);
+}
+
+void Exception::partiallyUnwindContext(ExecutionContext *catchingContext)
+{
+ if (!throwingContext)
+ return;
+ ExecutionContext *context = throwingContext;
+ while (context != catchingContext)
+ context = context->engine->popContext();
+ throwingContext = context;
+}
diff --git a/src/qml/qml/v4/qv4engine_p.h b/src/qml/qml/v4/qv4engine_p.h
index 96188d44a2..e7abf3c6a1 100644
--- a/src/qml/qml/v4/qv4engine_p.h
+++ b/src/qml/qml/v4/qv4engine_p.h
@@ -200,7 +200,8 @@ struct Q_QML_EXPORT ExecutionEngine
String *id_uintMax;
String *id_name;
- QVector<Function *> functions;
+ mutable QVector<Function *> functions;
+ mutable bool functionsNeedSort;
ExternalResourceComparison externalResourceComparison;
@@ -278,7 +279,8 @@ struct Q_QML_EXPORT ExecutionEngine
int line;
int column;
};
- QVector<StackFrame> stackTrace(int frameLimit = -1) const;
+ typedef QVector<StackFrame> StackTrace;
+ StackTrace stackTrace(int frameLimit = -1) const;
StackFrame currentStackFrame() const;
void requireArgumentsAccessors(int n);
@@ -288,6 +290,8 @@ struct Q_QML_EXPORT ExecutionEngine
void initRootContext();
InternalClass *newClass(const InternalClass &other);
+
+ Function *functionForProgramCounter(quintptr pc) const;
};
inline void ExecutionEngine::pushContext(SimpleCallContext *context)
@@ -309,6 +313,28 @@ inline ExecutionContext *ExecutionEngine::popContext()
return current;
}
+struct Q_QML_EXPORT Exception {
+ explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line);
+ ~Exception();
+
+ void accept(ExecutionContext *catchingContext);
+
+ void partiallyUnwindContext(ExecutionContext *catchingContext);
+
+ Value value() const { return exception; }
+ QUrl file() const { return m_file; }
+ int lineNumber() const { return m_line; }
+
+ ExecutionEngine::StackTrace stackTrace() const { return m_stackTrace; }
+
+private:
+ ExecutionContext *throwingContext;
+ bool accepted;
+ PersistentValue exception;
+ QUrl m_file;
+ int m_line;
+ ExecutionEngine::StackTrace m_stackTrace;
+};
} // namespace QV4
diff --git a/src/qml/qml/v4/qv4function.cpp b/src/qml/qml/v4/qv4function.cpp
index 9e29c9c9bb..86d0528783 100644
--- a/src/qml/qml/v4/qv4function.cpp
+++ b/src/qml/qml/v4/qv4function.cpp
@@ -65,3 +65,24 @@ void Function::mark()
for (int i = 0; i < identifiers.size(); ++i)
identifiers.at(i)->mark();
}
+
+namespace {
+
+bool operator<(const LineNumberMapping &mapping, quintptr pc)
+{
+ return mapping.codeOffset < pc;
+}
+
+}
+
+int Function::lineNumberForProgramCounter(quintptr pc) const
+{
+ quint32 offset = pc - reinterpret_cast<quintptr>(code);
+ QVector<LineNumberMapping>::ConstIterator it = qLowerBound(lineNumberMappings.begin(), lineNumberMappings.end(), offset);
+ if (it != lineNumberMappings.constBegin() && lineNumberMappings.count() > 0)
+ --it;
+ if (it == lineNumberMappings.constEnd())
+ return -1;
+ return it->lineNumber;
+}
+
diff --git a/src/qml/qml/v4/qv4function_p.h b/src/qml/qml/v4/qv4function_p.h
index e4a9cd9d7c..2df63f1bfe 100644
--- a/src/qml/qml/v4/qv4function_p.h
+++ b/src/qml/qml/v4/qv4function_p.h
@@ -80,6 +80,12 @@ struct URIErrorPrototype;
struct InternalClass;
struct Lookup;
+struct LineNumberMapping
+{
+ quint32 codeOffset;
+ int lineNumber;
+};
+
struct Function {
String *name;
@@ -104,6 +110,7 @@ struct Function {
bool isNamedExpression;
QUrl sourceFile;
+ QVector<LineNumberMapping> lineNumberMappings;
Function(String *name)
: name(name)
@@ -123,9 +130,12 @@ struct Function {
inline bool needsActivation() const { return hasNestedFunctions || hasDirectEval || usesArgumentsObject; }
void mark();
+
+ int lineNumberForProgramCounter(quintptr pc) const;
};
}
+Q_DECLARE_TYPEINFO(QV4::LineNumberMapping, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4isel_masm.cpp b/src/qml/qml/v4/qv4isel_masm.cpp
index 69df2aa848..bddf6d4c9b 100644
--- a/src/qml/qml/v4/qv4isel_masm.cpp
+++ b/src/qml/qml/v4/qv4isel_masm.cpp
@@ -430,6 +430,15 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
}
#endif
+void Assembler::recordLineNumber(int lineNumber)
+{
+ CodeLineNumerMapping mapping;
+ mapping.location = label();
+ mapping.lineNumber = lineNumber;
+ codeLineNumberMappings << mapping;
+}
+
+
void Assembler::link(QV4::Function *vmFunc)
{
Label endOfCode = label();
@@ -455,6 +464,14 @@ void Assembler::link(QV4::Function *vmFunc)
JSC::LinkBuffer linkBuffer(dummy, this, 0);
vmFunc->codeSize = linkBuffer.offsetOf(endOfCode);
+ vmFunc->lineNumberMappings.resize(codeLineNumberMappings.count());
+ for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
+ QV4::LineNumberMapping mapping;
+ mapping.codeOffset = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
+ mapping.lineNumber = codeLineNumberMappings.at(i).lineNumber;
+ vmFunc->lineNumberMappings[i] = mapping;
+ }
+
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
@@ -782,6 +799,11 @@ void InstructionSelection::visitTry(V4IR::Try *t)
_as->jump(Assembler::ReturnValueRegister);
}
+void InstructionSelection::visitDebugAnnotation(V4IR::DebugAnnotation *annotation)
+{
+ _as->recordLineNumber(annotation->location.startLine);
+}
+
void InstructionSelection::callBuiltinFinishTry()
{
// This assumes that we're in code that was called by tryWrapper, so we return to try wrapper
diff --git a/src/qml/qml/v4/qv4isel_masm_p.h b/src/qml/qml/v4/qv4isel_masm_p.h
index bdd05e3790..277161fe5d 100644
--- a/src/qml/qml/v4/qv4isel_masm_p.h
+++ b/src/qml/qml/v4/qv4isel_masm_p.h
@@ -725,6 +725,8 @@ public:
void link(QV4::Function *vmFunc);
+ void recordLineNumber(int lineNumber);
+
private:
V4IR::Function *_function;
QV4::Function *_vmFunction;
@@ -741,6 +743,13 @@ private:
QHash<V4IR::BasicBlock *, QVector<DataLabelPtr> > _labelPatches;
QV4::ExecutionEngine *_engine;
+
+ struct CodeLineNumerMapping
+ {
+ Assembler::Label location;
+ int lineNumber;
+ };
+ QVector<CodeLineNumerMapping> codeLineNumberMappings;
};
class Q_QML_EXPORT InstructionSelection:
@@ -838,6 +847,7 @@ protected:
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
virtual void visitTry(V4IR::Try *);
+ virtual void visitDebugAnnotation(V4IR::DebugAnnotation *);
private:
#define isel_stringIfyx(s) #s
diff --git a/src/qml/qml/v4/qv4jsir.cpp b/src/qml/qml/v4/qv4jsir.cpp
index e94aa1be2f..33debeec88 100644
--- a/src/qml/qml/v4/qv4jsir.cpp
+++ b/src/qml/qml/v4/qv4jsir.cpp
@@ -221,6 +221,8 @@ struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor
// nothing to do for Try statements
}
+ virtual void visitDebugAnnotation(DebugAnnotation *) {}
+
// expressions
virtual void visitConst(Const *) {}
virtual void visitString(String *) {}
@@ -543,6 +545,11 @@ void Try::dump(QTextStream &out, Stmt::Mode mode)
out << " with the name " << exceptionVarName << " and go to L" << catchBlock->index << ';';
}
+void DebugAnnotation::dump(QTextStream &out, Mode mode)
+{
+ out << "// line: " << location.startLine << " ; column: " << location.startColumn;
+}
+
Function *Module::newFunction(const QString &name, Function *outer)
{
Function *f = new Function(this, outer, name);
@@ -851,6 +858,16 @@ Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QStrin
return t;
}
+Stmt *BasicBlock::DEBUGANNOTATION(const AST::SourceLocation &location)
+{
+ if (isTerminated())
+ return 0;
+
+ DebugAnnotation *t = function->New<DebugAnnotation>();
+ t->init(location);
+ statements.append(t);
+}
+
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
out << 'L' << index << ':' << endl;
diff --git a/src/qml/qml/v4/qv4jsir_p.h b/src/qml/qml/v4/qv4jsir_p.h
index abe24da828..8ec223d9dc 100644
--- a/src/qml/qml/v4/qv4jsir_p.h
+++ b/src/qml/qml/v4/qv4jsir_p.h
@@ -54,6 +54,7 @@
#include "qv4global_p.h"
#include <private/qqmljsmemorypool_p.h>
+#include <private/qqmljsastfwd_p.h>
#include <QtCore/QVector>
#include <QtCore/QString>
@@ -118,6 +119,7 @@ struct Jump;
struct CJump;
struct Ret;
struct Try;
+struct DebugAnnotation;
enum AluOp {
OpInvalid = 0,
@@ -198,6 +200,7 @@ struct StmtVisitor {
virtual void visitCJump(CJump *) = 0;
virtual void visitRet(Ret *) = 0;
virtual void visitTry(Try *) = 0;
+ virtual void visitDebugAnnotation(DebugAnnotation *) = 0;
};
struct Expr {
@@ -492,6 +495,7 @@ struct Stmt {
virtual CJump *asCJump() { return 0; }
virtual Ret *asRet() { return 0; }
virtual Try *asTry() { return 0; }
+ virtual DebugAnnotation *asDebugAnnotation() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
void destroyData() {
@@ -629,6 +633,20 @@ struct Try: Stmt {
virtual void dump(QTextStream &out, Mode mode);
};
+struct DebugAnnotation: Stmt {
+ AST::SourceLocation location;
+
+ void init(const AST::SourceLocation &location)
+ {
+ this->location = location;
+ }
+
+ virtual void accept(StmtVisitor *v) { v->visitDebugAnnotation(this); }
+ virtual DebugAnnotation *asDebugAnnotation() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
struct Q_QML_EXPORT Module {
MemoryPool pool;
QVector<Function *> functions;
@@ -768,6 +786,7 @@ struct BasicBlock {
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
Stmt *RET(Temp *expr);
Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName, Temp *exceptionVar);
+ Stmt *DEBUGANNOTATION(const AST::SourceLocation &location);
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
};
diff --git a/src/qml/qml/v4/qv4runtime.cpp b/src/qml/qml/v4/qv4runtime.cpp
index 4241dad5ff..d9ed491a57 100644
--- a/src/qml/qml/v4/qv4runtime.cpp
+++ b/src/qml/qml/v4/qv4runtime.cpp
@@ -69,38 +69,6 @@
using namespace QV4;
-
-Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line)
- : exception(exceptionValue)
- , m_line(line)
-{
- m_file = throwingContext->currentFileName();
- this->throwingContext = throwingContext->engine->current;
- accepted = false;
-}
-
-Exception::~Exception()
-{
- assert(accepted);
-}
-
-void Exception::accept(ExecutionContext *catchingContext)
-{
- assert(!accepted);
- accepted = true;
- partiallyUnwindContext(catchingContext);
-}
-
-void Exception::partiallyUnwindContext(ExecutionContext *catchingContext)
-{
- if (!throwingContext)
- return;
- ExecutionContext *context = throwingContext;
- while (context != catchingContext)
- context = context->engine->popContext();
- throwingContext = context;
-}
-
extern "C" {
void __qmljs_numberToString(QString *result, double num, int radix)
@@ -954,18 +922,7 @@ void __qmljs_throw(ExecutionContext *context, const Value &value, int line)
if (context->engine->debugger)
context->engine->debugger->aboutToThrow(value);
- for (ExecutionContext *ctx = context; ctx; ctx = ctx->parent) {
- if (CallContext *callCtx = ctx->asCallContext())
- if (FunctionObject *fobj = callCtx->function)
- if (Function *fun = fobj->function)
- UnwindHelper::ensureUnwindInfo(fun);
- for (ExecutionContext::EvalCode *code = ctx->currentEvalCode;
- code; code = code->next)
- UnwindHelper::ensureUnwindInfo(code->function);
- }
-
- if (context->engine->globalCode)
- UnwindHelper::ensureUnwindInfo(context->engine->globalCode);
+ UnwindHelper::prepareForUnwind(context);
#if USE(LIBUNWIND_DEBUG)
printf("about to throw exception. walking stack first with libunwind:\n");
diff --git a/src/qml/qml/v4/qv4runtime_p.h b/src/qml/qml/v4/qv4runtime_p.h
index b4a8b9c310..42e3669834 100644
--- a/src/qml/qml/v4/qv4runtime_p.h
+++ b/src/qml/qml/v4/qv4runtime_p.h
@@ -89,27 +89,6 @@ struct ArrayObject;
struct ErrorObject;
struct ExecutionEngine;
struct InternalClass;
-
-struct Q_QML_EXPORT Exception {
- explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line);
- ~Exception();
-
- void accept(ExecutionContext *catchingContext);
-
- void partiallyUnwindContext(ExecutionContext *catchingContext);
-
- Value value() const { return exception; }
- QUrl file() const { return m_file; }
- int lineNumber() const { return m_line; }
-
-private:
- ExecutionContext *throwingContext;
- bool accepted;
- PersistentValue exception;
- QUrl m_file;
- int m_line;
-};
-
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4script_p.h b/src/qml/qml/v4/qv4script_p.h
index 8b2f3ede4e..53eeda0b92 100644
--- a/src/qml/qml/v4/qv4script_p.h
+++ b/src/qml/qml/v4/qv4script_p.h
@@ -51,11 +51,11 @@ namespace QV4 {
struct ExecutionContext;
struct Q_QML_EXPORT Script {
- Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 0, int column = 0)
+ Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, scope(scope), strictMode(false), inheritContext(false), parsed(false), qml(0)
, vmFunction(0) {}
- Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 0, int column = 0)
+ Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, scope(engine->rootContext), strictMode(true), inheritContext(true), parsed(false)
, qml(qml), vmFunction(0) {}
diff --git a/src/qml/qml/v4/qv4unwindhelper.cpp b/src/qml/qml/v4/qv4unwindhelper.cpp
index 3d54ea277a..0d8b21126e 100644
--- a/src/qml/qml/v4/qv4unwindhelper.cpp
+++ b/src/qml/qml/v4/qv4unwindhelper.cpp
@@ -29,7 +29,7 @@
#ifdef USE_NULL_HELPER
using namespace QV4;
-void UnwindHelper::ensureUnwindInfo(Function *function) {Q_UNUSED(function);}
+void UnwindHelper::prepareForUnwind(ExecutionContext *) {}
void UnwindHelper::registerFunction(Function *function) {Q_UNUSED(function);}
void UnwindHelper::registerFunctions(const QVector<Function *> &functions) {Q_UNUSED(functions);}
void UnwindHelper::deregisterFunction(Function *function) {Q_UNUSED(function);}
diff --git a/src/qml/qml/v4/qv4unwindhelper_p-arm.h b/src/qml/qml/v4/qv4unwindhelper_p-arm.h
index 7055c3a152..88cf11477d 100644
--- a/src/qml/qml/v4/qv4unwindhelper_p-arm.h
+++ b/src/qml/qml/v4/qv4unwindhelper_p-arm.h
@@ -116,9 +116,8 @@ void UnwindHelper::registerFunctions(const QVector<Function *> &functions)
allFunctions.insert(reinterpret_cast<quintptr>(f->code), f);
}
-void UnwindHelper::ensureUnwindInfo(Function *function)
+void UnwindHelper::prepareForUnwind(ExecutionContext *)
{
- Q_UNUSED(function);
}
int UnwindHelper::unwindInfoSize()
diff --git a/src/qml/qml/v4/qv4unwindhelper_p-dw2.h b/src/qml/qml/v4/qv4unwindhelper_p-dw2.h
index 0e4296769c..7941a0dd39 100644
--- a/src/qml/qml/v4/qv4unwindhelper_p-dw2.h
+++ b/src/qml/qml/v4/qv4unwindhelper_p-dw2.h
@@ -84,7 +84,7 @@ UnwindInfo::~UnwindInfo()
__deregister_frame(data.data() + fde_offset);
}
-void UnwindHelper::ensureUnwindInfo(Function *f)
+static void ensureUnwindInfo(Function *f)
{
if (!f->codeRef)
return; // Not a JIT generated function
@@ -112,6 +112,22 @@ void UnwindHelper::ensureUnwindInfo(Function *f)
chunk->unwindInfo = new UnwindInfo(info);
}
+void UnwindHelper::prepareForUnwind(ExecutionContext *context)
+{
+ for (ExecutionContext *ctx = context; ctx; ctx = ctx->parent) {
+ if (CallContext *callCtx = ctx->asCallContext())
+ if (FunctionObject *fobj = callCtx->function)
+ if (Function *fun = fobj->function)
+ ensureUnwindInfo(fun);
+ for (ExecutionContext::EvalCode *code = ctx->currentEvalCode;
+ code; code = code->next)
+ ensureUnwindInfo(code->function);
+ }
+
+ if (context->engine->globalCode)
+ ensureUnwindInfo(context->engine->globalCode);
+}
+
void UnwindHelper::registerFunction(Function *)
{
}
diff --git a/src/qml/qml/v4/qv4unwindhelper_p.h b/src/qml/qml/v4/qv4unwindhelper_p.h
index 7949278aad..0c2061309f 100644
--- a/src/qml/qml/v4/qv4unwindhelper_p.h
+++ b/src/qml/qml/v4/qv4unwindhelper_p.h
@@ -6,11 +6,12 @@
namespace QV4 {
struct Function;
+struct ExecutionContext;
class UnwindHelper
{
public:
- static void ensureUnwindInfo(Function *function);
+ static void prepareForUnwind(ExecutionContext *ctx);
static void registerFunction(Function *function);
static void registerFunctions(const QVector<Function *> &functions);
static void deregisterFunction(Function *function);
diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp
index 56ec2da7af..ead057c86a 100644
--- a/tools/v4/main.cpp
+++ b/tools/v4/main.cpp
@@ -120,26 +120,32 @@ DEFINE_MANAGED_VTABLE(GC);
} // builtins
-static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exception)
+static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exception)
{
- QV4::ErrorObject *e = exception.asErrorObject();
+ QV4::ErrorObject *e = exception.value().asErrorObject();
if (!e) {
- std::cerr << "Uncaught exception: " << qPrintable(exception.toString(ctx)->toQString()) << std::endl;
- return;
- }
+ std::cerr << "Uncaught exception: " << qPrintable(exception.value().toString(ctx)->toQString()) << std::endl;
+ } else {
+ if (QV4::SyntaxErrorObject *err = e->asSyntaxError()) {
+ QV4::DiagnosticMessage *msg = err->message();
+ if (!msg) {
+ std::cerr << "Uncaught exception: Syntax error" << std::endl;
+ return;
+ }
- if (QV4::SyntaxErrorObject *err = e->asSyntaxError()) {
- QV4::DiagnosticMessage *msg = err->message();
- if (!msg) {
- std::cerr << "Uncaught exception: Syntax error" << std::endl;
- return;
+ for (; msg; msg = msg->next) {
+ std::cerr << qPrintable(msg->buildFullMessage(ctx)->toQString()) << std::endl;
+ }
+ } else {
+ std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx, ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
}
+ }
- for (; msg; msg = msg->next) {
- std::cerr << qPrintable(msg->buildFullMessage(ctx)->toQString()) << std::endl;
- }
- } else {
- std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx, ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
+ foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) {
+ std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source.toLocalFile());
+ if (frame.line >= 0)
+ std::cerr << ":" << frame.line;
+ std::cerr << ")" << std::endl;
}
}
@@ -390,7 +396,7 @@ int main(int argc, char *argv[])
}
} catch (QV4::Exception& ex) {
ex.accept(ctx);
- showException(ctx, ex.value());
+ showException(ctx, ex);
return EXIT_FAILURE;
}