diff options
-rw-r--r-- | src/qml/qml/v4/moth/qv4isel_moth_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4codegen.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4engine.cpp | 169 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4engine_p.h | 30 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4function.cpp | 21 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4function_p.h | 10 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4isel_masm.cpp | 22 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4isel_masm_p.h | 10 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4jsir.cpp | 17 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4jsir_p.h | 19 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4runtime.cpp | 45 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4runtime_p.h | 21 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4script_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4unwindhelper.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4unwindhelper_p-arm.h | 3 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4unwindhelper_p-dw2.h | 18 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4unwindhelper_p.h | 3 | ||||
-rw-r--r-- | tools/v4/main.cpp | 38 |
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; } |