From 23f3fcbabc4959c5d05d821b25776f6344d9b42b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Oct 2015 16:58:04 +0200 Subject: QmlDebug: Split QV4::Debugging::Debugger ... into a pure interface and a QV4::Debugging::V4Debugger implementation. This is in preparation of a second implementation of this interface to be used with 'native mixed' debugging. Change-Id: I3078dcfe4bdee392a2d13ef43a55ca993e7b88d8 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4debugging.cpp | 48 +++++++++++++++++++------------------- src/qml/jsruntime/qv4debugging_p.h | 21 +++++++++++++---- src/qml/jsruntime/qv4engine.cpp | 4 ++-- src/qml/jsruntime/qv4engine_p.h | 2 +- 4 files changed, 44 insertions(+), 31 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 79fd58f700..7706a40da6 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; using namespace QV4::Debugging; -Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, +V4Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script) : engine(engine) , frameNr(frameNr) @@ -62,7 +62,7 @@ Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr , resultIsException(false) {} -void Debugger::JavaScriptJob::run() +void V4Debugger::JavaScriptJob::run() { Scope scope(engine); @@ -92,18 +92,18 @@ void Debugger::JavaScriptJob::run() handleResult(result); } -bool Debugger::JavaScriptJob::hasExeption() const +bool V4Debugger::JavaScriptJob::hasExeption() const { return resultIsException; } -class EvalJob: public Debugger::JavaScriptJob +class EvalJob: public V4Debugger::JavaScriptJob { bool result; public: EvalJob(QV4::ExecutionEngine *engine, const QString &script) - : Debugger::JavaScriptJob(engine, /*frameNr*/-1, script) + : V4Debugger::JavaScriptJob(engine, /*frameNr*/-1, script) , result(false) {} @@ -118,7 +118,7 @@ public: } }; -Debugger::Debugger(QV4::ExecutionEngine *engine) +V4Debugger::V4Debugger(QV4::ExecutionEngine *engine) : m_engine(engine) , m_state(Running) , m_stepping(NotStepping) @@ -129,11 +129,11 @@ Debugger::Debugger(QV4::ExecutionEngine *engine) , m_gatherSources(0) , m_runningJob(0) { - qMetaTypeId(); + qMetaTypeId(); qMetaTypeId(); } -void Debugger::pause() +void V4Debugger::pause() { QMutexLocker locker(&m_lock); if (m_state == Paused) @@ -141,7 +141,7 @@ void Debugger::pause() m_pauseRequested = true; } -void Debugger::resume(Speed speed) +void V4Debugger::resume(Speed speed) { QMutexLocker locker(&m_lock); if (m_state != Paused) @@ -155,28 +155,28 @@ void Debugger::resume(Speed speed) m_runningCondition.wakeAll(); } -void Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition) +void V4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition) { QMutexLocker locker(&m_lock); m_breakPoints.insert(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber), condition); m_haveBreakPoints = true; } -void Debugger::removeBreakPoint(const QString &fileName, int lineNumber) +void V4Debugger::removeBreakPoint(const QString &fileName, int lineNumber) { QMutexLocker locker(&m_lock); m_breakPoints.remove(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber)); m_haveBreakPoints = !m_breakPoints.isEmpty(); } -void Debugger::setBreakOnThrow(bool onoff) +void V4Debugger::setBreakOnThrow(bool onoff) { QMutexLocker locker(&m_lock); m_breakOnThrow = onoff; } -Debugger::ExecutionState Debugger::currentExecutionState() const +V4Debugger::ExecutionState V4Debugger::currentExecutionState() const { ExecutionState state; state.fileName = getFunction()->sourceFile(); @@ -185,12 +185,12 @@ Debugger::ExecutionState Debugger::currentExecutionState() const return state; } -QVector Debugger::stackTrace(int frameLimit) const +QVector V4Debugger::stackTrace(int frameLimit) const { return m_engine->stackTrace(frameLimit); } -void Debugger::maybeBreakAtInstruction() +void V4Debugger::maybeBreakAtInstruction() { if (m_runningJob) // do not re-enter when we're doing a job for the debugger. return; @@ -228,7 +228,7 @@ void Debugger::maybeBreakAtInstruction() } } -void Debugger::enteringFunction() +void V4Debugger::enteringFunction() { if (m_runningJob) return; @@ -239,7 +239,7 @@ void Debugger::enteringFunction() } } -void Debugger::leavingFunction(const ReturnedValue &retVal) +void V4Debugger::leavingFunction(const ReturnedValue &retVal) { if (m_runningJob) return; @@ -254,7 +254,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) } } -void Debugger::aboutToThrow() +void V4Debugger::aboutToThrow() { if (!m_breakOnThrow) return; @@ -266,7 +266,7 @@ void Debugger::aboutToThrow() pauseAndWait(Throwing); } -Function *Debugger::getFunction() const +Function *V4Debugger::getFunction() const { Scope scope(m_engine); ExecutionContext *context = m_engine->currentContext; @@ -277,7 +277,7 @@ Function *Debugger::getFunction() const return context->d()->engine->globalCode; } -void Debugger::pauseAndWait(PauseReason reason) +void V4Debugger::pauseAndWait(PauseReason reason) { if (m_runningJob) return; @@ -298,7 +298,7 @@ void Debugger::pauseAndWait(PauseReason reason) m_state = Running; } -bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) +bool V4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) { BreakPoints::iterator it = m_breakPoints.find(DebuggerBreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr)); if (it == m_breakPoints.end()) @@ -316,13 +316,13 @@ bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) return evilJob.resultAsBoolean(); } -void Debugger::runInEngine(Debugger::Job *job) +void V4Debugger::runInEngine(V4Debugger::Job *job) { QMutexLocker locker(&m_lock); runInEngine_havingLock(job); } -void Debugger::runInEngine_havingLock(Debugger::Job *job) +void V4Debugger::runInEngine_havingLock(V4Debugger::Job *job) { Q_ASSERT(job); Q_ASSERT(m_runningJob == 0); @@ -333,7 +333,7 @@ void Debugger::runInEngine_havingLock(Debugger::Job *job) m_runningJob = 0; } -Debugger::Job::~Job() +V4Debugger::Job::~Job() { } diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index 9b07a31f26..fdc9cac24f 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -91,6 +91,19 @@ inline bool operator==(const DebuggerBreakPoint &a, const DebuggerBreakPoint &b) typedef QHash BreakPoints; class Q_QML_EXPORT Debugger : public QObject +{ + Q_OBJECT + +public: + virtual ~Debugger() {} + virtual bool pauseAtNextOpportunity() const = 0; + virtual void maybeBreakAtInstruction() = 0; + virtual void enteringFunction() = 0; + virtual void leavingFunction(const ReturnedValue &retVal) = 0; + virtual void aboutToThrow() = 0; +}; + +class Q_QML_EXPORT V4Debugger : public Debugger { Q_OBJECT public: @@ -131,7 +144,7 @@ public: NotStepping = FullThrottle }; - Debugger(ExecutionEngine *engine); + V4Debugger(ExecutionEngine *engine); ExecutionEngine *engine() const { return m_engine; } @@ -173,14 +186,14 @@ public: // execution hooks void aboutToThrow(); signals: - void sourcesCollected(QV4::Debugging::Debugger *self, const QStringList &sources, int seq); - void debuggerPaused(QV4::Debugging::Debugger *self, QV4::Debugging::PauseReason reason); + void sourcesCollected(QV4::Debugging::V4Debugger *self, const QStringList &sources, int seq); + void debuggerPaused(QV4::Debugging::V4Debugger *self, QV4::Debugging::PauseReason reason); private: // requires lock to be held void pauseAndWait(PauseReason reason); bool reallyHitTheBreakPoint(const QString &filename, int linenr); - void runInEngine_havingLock(Debugger::Job *job); + void runInEngine_havingLock(V4Debugger::Job *job); private: QV4::ExecutionEngine *m_engine; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6fe14da850..2732f360b3 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -518,10 +518,10 @@ ExecutionEngine::~ExecutionEngine() delete [] argumentsAccessors; } -void ExecutionEngine::enableDebugger() +void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_) { Q_ASSERT(!debugger); - debugger = new Debugging::Debugger(this); + debugger = debugger_; iselFactory.reset(new Moth::ISelFactory); } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index e94b417908..4640f3f4cc 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -366,7 +366,7 @@ public: ExecutionEngine(EvalISelFactory *iselFactory = 0); ~ExecutionEngine(); - void enableDebugger(); + void setDebugger(Debugging::Debugger *debugger); void enableProfiler(); ExecutionContext *pushGlobalContext(); -- cgit v1.2.3 From 5c64391fb4eb7c85634d08327e2cf82182260ac9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 15 Oct 2015 16:29:03 +0200 Subject: Only set V4 debugger when service is enabled Otherwise different debug services could steal each other's debugers. Change-Id: Ic0a50333d21c7d20a7124240ea598f8446400ae3 Reviewed-by: hjk --- src/qml/jsruntime/qv4engine.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 2732f360b3..82d94f569e 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -522,7 +522,6 @@ void ExecutionEngine::setDebugger(Debugging::Debugger *debugger_) { Q_ASSERT(!debugger); debugger = debugger_; - iselFactory.reset(new Moth::ISelFactory); } void ExecutionEngine::enableProfiler() -- cgit v1.2.3 From af390399c8017f69cfc9cdd4ef74144e6810fbe2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 14 Oct 2015 14:25:41 +0200 Subject: Fix a crash when copying array data Regression from 5.5. d()->arrayData->alloc can be larger, but never smaller than the allocation of the other's array data. Change-Id: I7d2265768f9d6e6298bfbba0d674a4d0e642422f Task-number: QTBUG-48727 Reviewed-by: Liang Qi Reviewed-by: Nikita Krupenko Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index ee3539c176..ba29d52bc6 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -1107,7 +1107,7 @@ void Object::copyArrayData(Object *other) dd->len = other->d()->arrayData->len; dd->offset = other->d()->arrayData->offset; } - memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, d()->arrayData->alloc*sizeof(Value)); + memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } -- cgit v1.2.3 From d74da0f5a69e73bda91bb4270169da86b22a37b3 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 15 Oct 2015 14:31:52 +0200 Subject: Properly resolve the context to create mutable bindings on This fixes a regression introduced in 5.5, where eval() calls in strict mode would still modify outer properties. Change-Id: I3ab70b45217eea16da68a4537e3c107b76794f2c Reviewed-by: Simon Hausmann Reviewed-by: Erik Verbruggen --- src/qml/jsruntime/qv4context.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 403beacf39..007bf92639 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -114,23 +114,32 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) Scope scope(this); // find the right context to create the binding on - ScopedObject activation(scope, d()->engine->globalObject); + ScopedObject activation(scope); ScopedContext ctx(scope, this); while (ctx) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); - if (!c->activation) - c->activation = scope.engine->newObject(); - activation = c->activation; + if (!activation) { + if (!c->activation) + c->activation = scope.engine->newObject(); + activation = c->activation; + } break; } case Heap::ExecutionContext::Type_QmlContext: { + // this is ugly, as it overrides the inner callcontext, but has to stay as long + // as bindings still get their own callcontext Heap::QmlContext *qml = static_cast(ctx->d()); activation = qml->qml; break; } + case Heap::ExecutionContext::Type_GlobalContext: { + if (!activation) + activation = scope.engine->globalObject; + break; + } default: break; } -- cgit v1.2.3 From dc5bf4275b6d40aefac038d57b3aea62a8be3d12 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 20 Oct 2015 11:55:57 +0200 Subject: JS: Math.random(): fix range to not include 1.0. [15.8.2.14] specifies that the Math.random() returns a number greator or equal to 0, but less than 1. Libc however defines it to be less than or equal to 1, so we have to divide the returned value by RAND_MAX+1. Of course, in order to do this, we need to widen them to 64bits ints. Task-number: QTBUG-48753 Change-Id: Ia4d808014dbf2a5575f4226779214bf0d5981f49 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4mathobject.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index f1face007c..3d3ac84576 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -277,10 +277,15 @@ Q_GLOBAL_STATIC(QThreadStorage, seedCreatedStorage); ReturnedValue MathObject::method_random(CallContext *context) { if (!seedCreatedStorage()->hasLocalData()) { - qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast(context)); + int msecs = QTime(0,0,0).msecsTo(QTime::currentTime()); + Q_ASSERT(msecs >= 0); + qsrand(uint(uint(msecs) ^ reinterpret_cast(context))); seedCreatedStorage()->setLocalData(new bool(true)); } - return Encode(qrand() / (double) RAND_MAX); + // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of + // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1. + qint64 upperLimit = qint64(RAND_MAX) + 1; + return Encode(qrand() / double(upperLimit)); } ReturnedValue MathObject::method_round(CallContext *context) -- cgit v1.2.3