diff options
-rw-r--r-- | src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp | 13 | ||||
-rw-r--r-- | src/script/api/qscriptcontextinfo.cpp | 10 | ||||
-rw-r--r-- | src/script/api/qscriptvalue.cpp | 8 | ||||
-rw-r--r-- | src/script/script.pro | 2 | ||||
-rw-r--r-- | tests/auto/qscriptcontext/tst_qscriptcontext.cpp | 12 | ||||
-rw-r--r-- | tests/auto/qscriptengine/tst_qscriptengine.cpp | 51 | ||||
-rw-r--r-- | tests/auto/qscriptvalue/tst_qscriptvalue.cpp | 5 |
7 files changed, 80 insertions, 21 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp index b3c229e..d8027ff 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp @@ -1168,8 +1168,17 @@ DEFINE_STUB_FUNCTION(int, timeout_check) globalData->exception = createInterruptedExecutionException(globalData); VM_THROW_EXCEPTION_AT_END(); } - - CHECK_FOR_EXCEPTION_AT_END(); +#ifdef QT_BUILD_SCRIPT_LIB + else { + // It's possible that the call to QtScript's implementation of + // TimeoutChecker::didTimeOut() caused an error to be thrown. + // In that case, didTimeOut() should still return false, since + // we don't want the interrupted-exception to override the + // user-thrown error. But we need to check for exception here, + // otherwise JSC would continue normal execution. + CHECK_FOR_EXCEPTION_AT_END(); + } +#endif return timeoutChecker->ticksUntilNextCheck(); } diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp index 0f9de1d..182bc4a 100644 --- a/src/script/api/qscriptcontextinfo.cpp +++ b/src/script/api/qscriptcontextinfo.cpp @@ -159,12 +159,20 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte JSC::CodeBlock *codeBlock = frame->codeBlock(); if (returnPC && codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { #if ENABLE(JIT) - unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); + JSC::JITCode code = codeBlock->getJITCode(); + unsigned jitOffset = code.offsetOf(JSC::ReturnAddressPtr(returnPC).value()); + // We can only use the JIT code offset if it's smaller than the JIT size; + // otherwise calling getBytecodeIndex() is meaningless. + if (jitOffset < code.size()) { + unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); #else unsigned bytecodeOffset = returnPC - codeBlock->instructions().begin(); #endif bytecodeOffset--; //because returnPC is on the next instruction. We want the current one lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame), bytecodeOffset); +#if ENABLE(JIT) + } +#endif } } } diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 6037374..079cf92 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -536,7 +536,12 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) Q_D(QScriptValue); if (!d || !d->isObject()) return; - if (prototype.isValid() && QScriptValuePrivate::getEngine(prototype) + + JSC::JSValue other = d->engine->scriptValueToJSCValue(prototype); + if (!other || !(other.isObject() || other.isNull())) + return; + + if (QScriptValuePrivate::getEngine(prototype) && (QScriptValuePrivate::getEngine(prototype) != d->engine)) { qWarning("QScriptValue::setPrototype() failed: " "cannot set a prototype created in " @@ -544,7 +549,6 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) return; } JSC::JSObject *thisObject = JSC::asObject(d->jscValue); - JSC::JSValue other = d->engine->scriptValueToJSCValue(prototype); // check for cycle JSC::JSValue nextPrototypeValue = other; diff --git a/src/script/script.pro b/src/script/script.pro index ce5c778..c558ba8 100644 --- a/src/script/script.pro +++ b/src/script/script.pro @@ -73,7 +73,7 @@ INCLUDEPATH += $$WEBKITDIR/JavaScriptCore/generated # This line copied from WebCore.pro DEFINES += WTF_USE_JAVASCRIPTCORE_BINDINGS=1 WTF_CHANGES=1 -DEFINES += NDEBUG +CONFIG(release, debug|release):DEFINES += NDEBUG solaris-g++:isEqual(QT_ARCH,sparc) { CONFIG -= separate_debug_info diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp index 9d7e896..457188c 100644 --- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp +++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp @@ -725,10 +725,7 @@ void tst_QScriptContext::backtrace_data() expected << "<native>('hey') at -1" << "<eval>() at 3" - << QString::fromLatin1("foo(arg1 = 'hello', arg2 = 456) at testfile:%0") - // interpreter unfortunately doesn't provide line number for eval() - .arg(qt_script_isJITEnabled() ? 2 : -1); - expected + << "foo(arg1 = 'hello', arg2 = 456) at testfile:2" << "<global>() at testfile:4"; QTest::newRow("eval") << source << expected; @@ -787,10 +784,7 @@ void tst_QScriptContext::backtrace_data() expected << "<native>('hey') at -1" << "<eval>() at 3" - << QString::fromLatin1("plop('hello', 456) at testfile:%0") - // interpreter unfortunately doesn't provide line number for eval() - .arg(qt_script_isJITEnabled() ? 3 : -1); - expected + << "plop('hello', 456) at testfile:3" << "<global>() at testfile:5"; QTest::newRow("eval in member") << source << expected; @@ -987,6 +981,8 @@ void tst_QScriptContext::backtrace() QVERIFY(!eng.hasUncaughtException()); QVERIFY(ret.isArray()); QStringList slist = qscriptvalue_cast<QStringList>(ret); + QEXPECT_FAIL("eval", "QTBUG-17842: Missing line number in backtrace when function calls eval()", Continue); + QEXPECT_FAIL("eval in member", "QTBUG-17842: Missing line number in backtrace when function calls eval()", Continue); QCOMPARE(slist, expectedbacktrace); } diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 1de34b4..bc4091d 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -157,6 +157,7 @@ private slots: void reportAdditionalMemoryCost(); void gcWithNestedDataStructure(); void processEventsWhileRunning(); + void throwErrorFromProcessEvents_data(); void throwErrorFromProcessEvents(); void disableProcessEventsInterval(); void stacktrace(); @@ -164,6 +165,7 @@ private slots: void numberParsing(); void automaticSemicolonInsertion(); void abortEvaluation_notEvaluating(); + void abortEvaluation_data(); void abortEvaluation(); void abortEvaluation_tryCatch(); void abortEvaluation_fromNative(); @@ -2962,17 +2964,42 @@ public: QScriptEngine *engine; }; +void tst_QScriptEngine::throwErrorFromProcessEvents_data() +{ + QTest::addColumn<QString>("script"); + QTest::addColumn<QString>("error"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }") + << QString::fromLatin1("Error: Killed"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }") + << QString::fromLatin1("Error: Killed"); + // Unlike abortEvaluation(), scripts should be able to catch the + // exception. + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}") + << QString::fromLatin1("Error: Caught"); +} + void tst_QScriptEngine::throwErrorFromProcessEvents() { + QFETCH(QString, script); + QFETCH(QString, error); + QScriptEngine eng; EventReceiver2 receiver(&eng); QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); eng.setProcessEventsInterval(100); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed")); + QCOMPARE(ret.toString(), error); } void tst_QScriptEngine::disableProcessEventsInterval() @@ -3387,8 +3414,26 @@ void tst_QScriptEngine::abortEvaluation_notEvaluating() } } +void tst_QScriptEngine::abortEvaluation_data() +{ + QTest::addColumn<QString>("script"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }"); + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}"); +} + void tst_QScriptEngine::abortEvaluation() { + QFETCH(QString, script); + QScriptEngine eng; EventReceiver3 receiver(&eng); @@ -3396,7 +3441,7 @@ void tst_QScriptEngine::abortEvaluation() for (int x = 0; x < 4; ++x) { QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); receiver.resultType = EventReceiver3::AbortionResult(x); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); switch (receiver.resultType) { case EventReceiver3::None: QVERIFY(!eng.hasUncaughtException()); diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp index 9014241..6686e2d 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp @@ -2328,8 +2328,7 @@ void tst_QScriptValue::getSetPrototype_invalidPrototype() inv.setPrototype(object); QCOMPARE(inv.prototype().isValid(), false); object.setPrototype(inv); - // FIXME should it be invalid or proto? - QVERIFY(object.prototype().strictlyEquals(inv)); + QVERIFY(object.prototype().strictlyEquals(proto)); } void tst_QScriptValue::getSetPrototype_twoEngines() @@ -2367,8 +2366,6 @@ void tst_QScriptValue::getSetPrototype_notObjectOrNull() QScriptValue object = eng.newObject(); QScriptValue originalProto = object.prototype(); - QEXPECT_FAIL("", "QTBUG-15154: QScriptValue::setPrototype() allows a non-Object value to be set as prototype", Abort); - // bool object.setPrototype(true); QVERIFY(object.prototype().equals(originalProto)); |