diff options
Diffstat (limited to 'JavaScriptCore/qt')
17 files changed, 1100 insertions, 11 deletions
diff --git a/JavaScriptCore/qt/ChangeLog b/JavaScriptCore/qt/ChangeLog new file mode 100644 index 0000000..8f2d423 --- /dev/null +++ b/JavaScriptCore/qt/ChangeLog @@ -0,0 +1,59 @@ +2010-07-02 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Simon Hausmann. + + Compilation fix. + + QScriptEnginePrivate::newArray can't be const because it can + throw an exception. + + [Qt] QScriptEnginePrivate compilation fix + https://bugs.webkit.org/show_bug.cgi?id=41520 + + * api/qscriptengine_p.cpp: + (QScriptEnginePrivate::newArray): + * api/qscriptengine_p.h: + +2010-06-28 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Simon Hausmann. + + Implement exception reporting in the QtScript API. + + The exception should be accessible through the API by the uncaughtException + function. Functions; hasUncaughtException, clearExceptions, uncaughtExceptionLineNumber, + uncaughtExceptionBacktrace were added to facilitate error checking and debugging. + + [Qt] QtScript API should be exceptions aware. + https://bugs.webkit.org/show_bug.cgi?id=41199 + + * api/qscriptengine.cpp: + (QScriptEngine::hasUncaughtException): + (QScriptEngine::uncaughtException): + (QScriptEngine::clearExceptions): + (QScriptEngine::uncaughtExceptionLineNumber): + (QScriptEngine::uncaughtExceptionBacktrace): + * api/qscriptengine.h: + * api/qscriptengine_p.cpp: + (QScriptEnginePrivate::QScriptEnginePrivate): + (QScriptEnginePrivate::~QScriptEnginePrivate): + (QScriptEnginePrivate::uncaughtException): + * api/qscriptengine_p.h: + (QScriptEnginePrivate::): + (QScriptEnginePrivate::evaluate): + (QScriptEnginePrivate::hasUncaughtException): + (QScriptEnginePrivate::clearExceptions): + (QScriptEnginePrivate::setException): + (QScriptEnginePrivate::uncaughtExceptionLineNumber): + (QScriptEnginePrivate::uncaughtExceptionBacktrace): + * api/qscriptvalue_p.h: + (QScriptValuePrivate::toString): + (QScriptValuePrivate::toNumber): + (QScriptValuePrivate::toObject): + (QScriptValuePrivate::equals): + (QScriptValuePrivate::instanceOf): + (QScriptValuePrivate::call): + (QScriptValuePrivate::inherits): + * tests/qscriptengine/tst_qscriptengine.cpp: + (tst_QScriptEngine::uncaughtException): + diff --git a/JavaScriptCore/qt/api/qscriptengine.cpp b/JavaScriptCore/qt/api/qscriptengine.cpp index e1bdf77..4b2319b 100644 --- a/JavaScriptCore/qt/api/qscriptengine.cpp +++ b/JavaScriptCore/qt/api/qscriptengine.cpp @@ -96,6 +96,71 @@ QScriptValue QScriptEngine::evaluate(const QScriptProgram& program) } /*! + Returns true if the last script evaluation resulted in an uncaught + exception; otherwise returns false. + + The exception state is cleared when evaluate() is called. + + \sa uncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +bool QScriptEngine::hasUncaughtException() const +{ + return d_ptr->hasUncaughtException(); +} + +/*! + Returns the current uncaught exception, or an invalid QScriptValue + if there is no uncaught exception. + + The exception value is typically an \c{Error} object; in that case, + you can call toString() on the return value to obtain an error + message. + + \sa hasUncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +QScriptValue QScriptEngine::uncaughtException() const +{ + return QScriptValuePrivate::get(d_ptr->uncaughtException()); +} + +/*! + Clears any uncaught exceptions in this engine. + + \sa hasUncaughtException() +*/ +void QScriptEngine::clearExceptions() +{ + d_ptr->clearExceptions(); +} + +/*! + Returns the line number where the last uncaught exception occurred. + + Line numbers are 1-based, unless a different base was specified as + the second argument to evaluate(). + + \sa hasUncaughtException(), uncaughtExceptionBacktrace() +*/ +int QScriptEngine::uncaughtExceptionLineNumber() const +{ + return d_ptr->uncaughtExceptionLineNumber(); +} + +/*! + Returns a human-readable backtrace of the last uncaught exception. + + Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}. + + \sa uncaughtException() +*/ +QStringList QScriptEngine::uncaughtExceptionBacktrace() const +{ + return d_ptr->uncaughtExceptionBacktrace(); +} + +/*! Runs the garbage collector. The garbage collector will attempt to reclaim memory by locating and disposing of objects that are @@ -206,6 +271,16 @@ QScriptValue QScriptEngine::newObject() } /*! + Creates a QtScript object of class Array with the given \a length. + + \sa newObject() +*/ +QScriptValue QScriptEngine::newArray(uint length) +{ + return QScriptValuePrivate::get(d_ptr->newArray(length)); +} + +/*! Returns this engine's Global Object. By default, the Global Object contains the built-in objects that are diff --git a/JavaScriptCore/qt/api/qscriptengine.h b/JavaScriptCore/qt/api/qscriptengine.h index 653dffe..1a87a37 100644 --- a/JavaScriptCore/qt/api/qscriptengine.h +++ b/JavaScriptCore/qt/api/qscriptengine.h @@ -42,6 +42,12 @@ public: QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1); QScriptValue evaluate(const QScriptProgram& program); + bool hasUncaughtException() const; + QScriptValue uncaughtException() const; + void clearExceptions(); + int uncaughtExceptionLineNumber() const; + QStringList uncaughtExceptionBacktrace() const; + void collectGarbage(); void reportAdditionalMemoryCost(int cost); @@ -51,6 +57,7 @@ public: QScriptValue nullValue(); QScriptValue undefinedValue(); QScriptValue newObject(); + QScriptValue newArray(uint length = 0); QScriptValue globalObject() const; private: friend class QScriptEnginePrivate; diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp index fd7978b..23e41c4 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.cpp +++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp @@ -31,11 +31,14 @@ QScriptEnginePrivate::QScriptEnginePrivate(const QScriptEngine* engine) : q_ptr(const_cast<QScriptEngine*>(engine)) , m_context(JSGlobalContextCreate(0)) + , m_exception(0) { } QScriptEnginePrivate::~QScriptEnginePrivate() { + if (m_exception) + JSValueUnprotect(m_context, m_exception); JSGlobalContextRelease(m_context); } @@ -77,11 +80,35 @@ QScriptValuePrivate* QScriptEnginePrivate::evaluate(const QScriptProgramPrivate* return new QScriptValuePrivate(this, evaluate(*program, program->file(), program->line())); } +QScriptValuePrivate* QScriptEnginePrivate::uncaughtException() const +{ + return m_exception ? new QScriptValuePrivate(this, m_exception) : new QScriptValuePrivate(); +} + QScriptValuePrivate* QScriptEnginePrivate::newObject() const { return new QScriptValuePrivate(this, JSObjectMake(m_context, /* jsClass */ 0, /* userData */ 0)); } +QScriptValuePrivate* QScriptEnginePrivate::newArray(uint length) +{ + JSValueRef exception = 0; + JSObjectRef array = JSObjectMakeArray(m_context, /* argumentCount */ 0, /* arguments */ 0, &exception); + + if (!exception) { + if (length > 0) { + JSRetainPtr<JSStringRef> lengthRef(Adopt, JSStringCreateWithUTF8CString("length")); + // array is an Array instance, so an exception should not occure here. + JSObjectSetProperty(m_context, array, lengthRef.get(), JSValueMakeNumber(m_context, length), kJSPropertyAttributeNone, /* exception */ 0); + } + } else { + setException(exception, NotNullException); + return new QScriptValuePrivate(); + } + + return new QScriptValuePrivate(this, array); +} + QScriptValuePrivate* QScriptEnginePrivate::globalObject() const { JSObjectRef globalObject = JSContextGetGlobalObject(m_context); diff --git a/JavaScriptCore/qt/api/qscriptengine_p.h b/JavaScriptCore/qt/api/qscriptengine_p.h index 9083f7d..30ee039 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.h +++ b/JavaScriptCore/qt/api/qscriptengine_p.h @@ -26,9 +26,11 @@ #include "qscriptsyntaxcheckresult_p.h" #include "qscriptvalue.h" #include <JavaScriptCore/JavaScript.h> +#include <JavaScriptCore/JSRetainPtr.h> #include <JSBasePrivate.h> #include <QtCore/qshareddata.h> #include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> class QScriptEngine; class QScriptSyntaxCheckResultPrivate; @@ -41,11 +43,23 @@ public: QScriptEnginePrivate(const QScriptEngine*); ~QScriptEnginePrivate(); + enum SetExceptionFlag { + IgnoreNullException = 0x01, + NotNullException = 0x02, + }; + QScriptSyntaxCheckResultPrivate* checkSyntax(const QString& program); QScriptValuePrivate* evaluate(const QString& program, const QString& fileName, int lineNumber); QScriptValuePrivate* evaluate(const QScriptProgramPrivate* program); inline JSValueRef evaluate(JSStringRef program, JSStringRef fileName, int lineNumber); + inline bool hasUncaughtException() const; + QScriptValuePrivate* uncaughtException() const; + inline void clearExceptions(); + inline void setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags = IgnoreNullException); + inline int uncaughtExceptionLineNumber() const; + inline QStringList uncaughtExceptionBacktrace() const; + inline void collectGarbage(); inline void reportAdditionalMemoryCost(int cost); @@ -57,6 +71,7 @@ public: inline JSValueRef makeJSValue(QScriptValue::SpecialValue value) const; QScriptValuePrivate* newObject() const; + QScriptValuePrivate* newArray(uint length); QScriptValuePrivate* globalObject() const; inline QScriptStringPrivate* toStringHandle(const QString& str) const; @@ -65,6 +80,7 @@ public: private: QScriptEngine* q_ptr; JSGlobalContextRef m_context; + JSValueRef m_exception; }; @@ -77,11 +93,67 @@ JSValueRef QScriptEnginePrivate::evaluate(JSStringRef program, JSStringRef fileN { JSValueRef exception; JSValueRef result = JSEvaluateScript(m_context, program, /* Global Object */ 0, fileName, lineNumber, &exception); - if (!result) + if (!result) { + setException(exception, NotNullException); return exception; // returns an exception + } + clearExceptions(); return result; } +bool QScriptEnginePrivate::hasUncaughtException() const +{ + return m_exception; +} + +void QScriptEnginePrivate::clearExceptions() +{ + if (m_exception) + JSValueUnprotect(m_context, m_exception); + m_exception = 0; +} + +void QScriptEnginePrivate::setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags) +{ + if (!((flags & NotNullException) || exception)) + return; + Q_ASSERT(exception); + + if (m_exception) + JSValueUnprotect(m_context, m_exception); + JSValueProtect(m_context, exception); + m_exception = exception; +} + +int QScriptEnginePrivate::uncaughtExceptionLineNumber() const +{ + if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception)) + return -1; + + JSValueRef exception = 0; + JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line")); + JSValueRef lineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception); + int result = JSValueToNumber(m_context, lineNumber, &exception); + return exception ? -1 : result; +} + +QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const +{ + if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception)) + return QStringList(); + + JSValueRef exception = 0; + JSRetainPtr<JSStringRef> fileNamePropertyName(Adopt, QScriptConverter::toString("sourceURL")); + JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line")); + JSValueRef jsFileName = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), fileNamePropertyName.get(), &exception); + JSValueRef jsLineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception); + JSRetainPtr<JSStringRef> fileName(Adopt, JSValueToStringCopy(m_context, jsFileName, &exception)); + int lineNumber = JSValueToNumber(m_context, jsLineNumber, &exception); + return QStringList(QString::fromLatin1("<anonymous>()@%0:%1") + .arg(QScriptConverter::toString(fileName.get())) + .arg(QScriptConverter::toString(exception ? -1 : lineNumber))); +} + void QScriptEnginePrivate::collectGarbage() { JSGarbageCollect(m_context); diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index 8ad76a5..e309fb7 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -627,3 +627,41 @@ bool QScriptValue::instanceOf(const QScriptValue& other) const { return d_ptr->instanceOf(QScriptValuePrivate::get(other)); } + +/*! + Returns the value of this QScriptValue's property with the given \a name, + using the given \a mode to resolve the property. + + If no such property exists, an invalid QScriptValue is returned. + + If the property is implemented using a getter function (i.e. has the + PropertyGetter flag set), calling property() has side-effects on the + script engine, since the getter function will be called (possibly + resulting in an uncaught script exception). If an exception + occurred, property() returns the value that was thrown (typically + an \c{Error} object). + + \sa setProperty(), propertyFlags(), QScriptValueIterator +*/ +QScriptValue QScriptValue::property(const QString& name, const ResolveFlags& mode) const +{ + return QScriptValuePrivate::get(d_ptr->property(name, mode)); +} + +/*! + \overload + + Returns the property at the given \a arrayIndex, using the given \a + mode to resolve the property. + + This function is provided for convenience and performance when + working with array objects. + + If this QScriptValue is not an Array object, this function behaves + as if property() was called with the string representation of \a + arrayIndex. +*/ +QScriptValue QScriptValue::property(quint32 arrayIndex, const ResolveFlags& mode) const +{ + return QScriptValuePrivate::get(d_ptr->property(arrayIndex, mode)); +} diff --git a/JavaScriptCore/qt/api/qscriptvalue.h b/JavaScriptCore/qt/api/qscriptvalue.h index c82ef55..c55d461 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.h +++ b/JavaScriptCore/qt/api/qscriptvalue.h @@ -32,7 +32,14 @@ typedef QList<QScriptValue> QScriptValueList; typedef double qsreal; class QScriptValue { -public: +public: + enum ResolveFlag { + ResolveLocal = 0x00, + ResolvePrototype = 0x01 + }; + + Q_DECLARE_FLAGS(ResolveFlags, ResolveFlag) + enum SpecialValue { NullValue, UndefinedValue @@ -67,6 +74,9 @@ public: bool strictlyEquals(const QScriptValue& other) const; bool instanceOf(const QScriptValue& other) const; + QScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; + QScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; + QScriptEngine* engine() const; bool isValid() const; diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index f8a1e7a..49bec97 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -120,6 +120,9 @@ public: inline bool instanceOf(QScriptValuePrivate* other); inline bool assignEngine(QScriptEnginePrivate* engine); + inline QScriptValuePrivate* property(const QString& name, const QScriptValue::ResolveFlags& mode); + inline QScriptValuePrivate* property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode); + inline QScriptValuePrivate* call(const QScriptValuePrivate* , const QScriptValueList& args); inline operator JSValueRef() const; @@ -442,7 +445,9 @@ QString QScriptValuePrivate::toString() const case JSValue: case JSPrimitive: case JSObject: - JSRetainPtr<JSStringRef> ptr(Adopt, JSValueToStringCopy(*m_engine, *this, /* exception */ 0)); + JSValueRef exception = 0; + JSRetainPtr<JSStringRef> ptr(Adopt, JSValueToStringCopy(*m_engine, *this, &exception)); + m_engine->setException(exception); return QScriptConverter::toString(ptr.get()); } @@ -456,7 +461,12 @@ qsreal QScriptValuePrivate::toNumber() const case JSValue: case JSPrimitive: case JSObject: - return JSValueToNumber(*m_engine, *this, /* exception */ 0); + { + JSValueRef exception = 0; + qsreal result = JSValueToNumber(*m_engine, *this, &exception); + m_engine->setException(exception); + return result; + } case CNumber: return u.m_number; case CBool: @@ -585,9 +595,13 @@ QScriptValuePrivate* QScriptValuePrivate::toObject(QScriptEnginePrivate* engine) { if (engine != this->engine()) qWarning("QScriptEngine::toObject: cannot convert value created in a different engine"); - JSObjectRef object = JSValueToObject(*m_engine, *this, /* exception */ 0); + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject(*m_engine, *this, &exception); if (object) return new QScriptValuePrivate(m_engine.constData(), object); + else + m_engine->setException(exception, QScriptEnginePrivate::NotNullException); + } return new QScriptValuePrivate; case JSObject: @@ -621,7 +635,7 @@ inline QScriptValuePrivate* QScriptValuePrivate::prototype() return new QScriptValuePrivate(engine(), prototype); // The prototype could be either a null or a JSObject, so it is safe to cast the prototype // to the JSObjectRef here. - return new QScriptValuePrivate(engine(), prototype, const_cast<JSObjectRef>(prototype)); + return new QScriptValuePrivate(engine(), const_cast<JSObjectRef>(prototype)); } return new QScriptValuePrivate; } @@ -672,7 +686,10 @@ bool QScriptValuePrivate::equals(QScriptValuePrivate* other) } } - return JSValueIsEqual(*m_engine, *this, *other, /* exception */ 0); + JSValueRef exception = 0; + bool result = JSValueIsEqual(*m_engine, *this, *other, &exception); + m_engine->setException(exception); + return result; } bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) @@ -716,7 +733,10 @@ inline bool QScriptValuePrivate::instanceOf(QScriptValuePrivate* other) { if (!isJSBased() || !other->isObject()) return false; - return JSValueIsInstanceOfConstructor(*m_engine, *this, *other, /* exception */ 0); + JSValueRef exception = 0; + bool result = JSValueIsInstanceOfConstructor(*m_engine, *this, *other, &exception); + m_engine->setException(exception); + return result; } /*! @@ -756,6 +776,35 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) return true; } +inline QScriptValuePrivate* QScriptValuePrivate::property(const QString& name, const QScriptValue::ResolveFlags& mode) +{ + if (!isObject()) + return new QScriptValuePrivate; + + if (mode & QScriptValue::ResolveLocal) { + qWarning("QScriptValue::property(): ResolveLocal not supported yet."); + return new QScriptValuePrivate; + } + + JSRetainPtr<JSStringRef> nameRef(Adopt, QScriptConverter::toString(name)); + QScriptValuePrivate* result = new QScriptValuePrivate(m_engine.constData(), JSObjectGetProperty(*m_engine, *this, nameRef.get(), /* exception */ 0)); + + return result; +} + +inline QScriptValuePrivate* QScriptValuePrivate::property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode) +{ + if (!isObject()) + return new QScriptValuePrivate; + + if (mode & QScriptValue::ResolveLocal) { + qWarning("QScriptValue::property(): ResolveLocal not supported yet."); + return new QScriptValuePrivate; + } + + return new QScriptValuePrivate(m_engine.constData(), JSObjectGetPropertyAtIndex(*m_engine, *this, arrayIndex, /* exception */ 0)); +} + QScriptValuePrivate* QScriptValuePrivate::call(const QScriptValuePrivate*, const QScriptValueList& args) { switch (m_state) { @@ -781,8 +830,10 @@ QScriptValuePrivate* QScriptValuePrivate::call(const QScriptValuePrivate*, const // Make the call JSValueRef exception = 0; JSValueRef result = JSObjectCallAsFunction(*m_engine, *this, /* thisObject */ 0, argc, argv.constData(), &exception); - if (!result && exception) + if (!result && exception) { + m_engine->setException(exception); return new QScriptValuePrivate(engine(), exception); + } if (result && !exception) return new QScriptValuePrivate(engine(), result); } @@ -823,9 +874,12 @@ bool QScriptValuePrivate::inherits(const char* name) Q_ASSERT(isJSBased()); JSObjectRef globalObject = JSContextGetGlobalObject(*m_engine); JSStringRef errorAttrName = QScriptConverter::toString(name); - JSValueRef error = JSObjectGetProperty(*m_engine, globalObject, errorAttrName, /* exception */ 0); + JSValueRef exception = 0; + JSValueRef error = JSObjectGetProperty(*m_engine, globalObject, errorAttrName, &exception); JSStringRelease(errorAttrName); - return JSValueIsInstanceOfConstructor(*m_engine, *this, JSValueToObject(*m_engine, error, /* exception */ 0), /* exception */ 0); + bool result = JSValueIsInstanceOfConstructor(*m_engine, *this, JSValueToObject(*m_engine, error, &exception), &exception); + m_engine->setException(exception); + return result; } /*! diff --git a/JavaScriptCore/qt/benchmarks/benchmarks.pri b/JavaScriptCore/qt/benchmarks/benchmarks.pri new file mode 100644 index 0000000..5af3383 --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/benchmarks.pri @@ -0,0 +1,19 @@ +QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR +QMAKE_LIBDIR = $$OUTPUT_DIR/lib $$QMAKE_LIBDIR +mac:!static:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework) { + LIBS += -framework QtScript + QMAKE_FRAMEWORKPATH = $$OUTPUT_DIR/lib $$QMAKE_FRAMEWORKPATH +} else { + win32-*|wince* { + LIBS += -lQtScript$${QT_MAJOR_VERSION} + } else { + LIBS += -lQtScript + } +} + +CONFIG(release, debug|release) { + DEFINES += NDEBUG +} + +INCLUDEPATH += $$PWD/../api + diff --git a/JavaScriptCore/qt/benchmarks/benchmarks.pro b/JavaScriptCore/qt/benchmarks/benchmarks.pro new file mode 100644 index 0000000..85fa82c --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/benchmarks.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = qscriptengine \ + qscriptvalue \ + diff --git a/JavaScriptCore/qt/benchmarks/qscriptengine/qscriptengine.pro b/JavaScriptCore/qt/benchmarks/qscriptengine/qscriptengine.pro new file mode 100644 index 0000000..e94137d --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/qscriptengine/qscriptengine.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = tst_bench_qscriptengine + +SOURCES += tst_qscriptengine.cpp + +QT += testlib + +include(../benchmarks.pri) + +symbian* { + TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 // Min 128kB, Max 32MB + TARGET.EPOCSTACKSIZE = 0x14000 +} diff --git a/JavaScriptCore/qt/benchmarks/qscriptengine/tst_qscriptengine.cpp b/JavaScriptCore/qt/benchmarks/qscriptengine/tst_qscriptengine.cpp new file mode 100644 index 0000000..0c447c6 --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/qscriptengine/tst_qscriptengine.cpp @@ -0,0 +1,142 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "qscriptengine.h" +#include "qscriptvalue.h" +#include <qtest.h> + +class tst_QScriptEngine : public QObject { + Q_OBJECT + +private slots: + void checkSyntax_data(); + void checkSyntax(); + void constructor(); + void evaluateString_data(); + void evaluateString(); + void evaluateProgram_data(); + void evaluateProgram(); + void newObject(); + void nullValue(); + void undefinedValue(); + void globalObject(); + void toStringHandle(); +}; + +void tst_QScriptEngine::checkSyntax_data() +{ + evaluateString_data(); +} + +void tst_QScriptEngine::checkSyntax() +{ + QFETCH(QString, code); + QScriptEngine engine; + QBENCHMARK { + engine.checkSyntax(code); + } +} + +void tst_QScriptEngine::constructor() +{ + QBENCHMARK { + QScriptEngine engine; + } +} + +void tst_QScriptEngine::evaluateString_data() +{ + QTest::addColumn<QString>("code"); + QTest::newRow("empty script") << QString::fromLatin1(""); + QTest::newRow("number literal") << QString::fromLatin1("123"); + QTest::newRow("string literal") << QString::fromLatin1("'ciao'"); + QTest::newRow("regexp literal") << QString::fromLatin1("/foo/gim"); + QTest::newRow("null literal") << QString::fromLatin1("null"); + QTest::newRow("undefined literal") << QString::fromLatin1("undefined"); + QTest::newRow("empty object literal") << QString::fromLatin1("{}"); + QTest::newRow("this") << QString::fromLatin1("this"); +} + +void tst_QScriptEngine::evaluateString() +{ + QFETCH(QString, code); + QScriptEngine engine; + QBENCHMARK { + engine.evaluate(code); + } +} + +void tst_QScriptEngine::evaluateProgram_data() +{ + evaluateString_data(); +} + +void tst_QScriptEngine::evaluateProgram() +{ + QFETCH(QString, code); + QScriptEngine engine; + QScriptProgram program(code); + QBENCHMARK { + engine.evaluate(program); + } +} + +void tst_QScriptEngine::newObject() +{ + QScriptEngine engine; + QBENCHMARK { + engine.newObject(); + } +} + +void tst_QScriptEngine::nullValue() +{ + QScriptEngine engine; + QBENCHMARK { + engine.nullValue(); + } +} + +void tst_QScriptEngine::undefinedValue() +{ + QScriptEngine engine; + QBENCHMARK { + engine.undefinedValue(); + } +} + +void tst_QScriptEngine::globalObject() +{ + QScriptEngine engine; + QBENCHMARK { + engine.globalObject(); + } +} + +void tst_QScriptEngine::toStringHandle() +{ + QScriptEngine engine; + QString str = QString::fromLatin1("foobarbaz"); + QBENCHMARK { + engine.toStringHandle(str); + } +} + +QTEST_MAIN(tst_QScriptEngine) +#include "tst_qscriptengine.moc" diff --git a/JavaScriptCore/qt/benchmarks/qscriptvalue/qscriptvalue.pro b/JavaScriptCore/qt/benchmarks/qscriptvalue/qscriptvalue.pro new file mode 100644 index 0000000..673fe65 --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/qscriptvalue/qscriptvalue.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +TARGET = tst_bench_qscriptvalue +QT += testlib + +isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../.. +include(../benchmarks.pri) + +SOURCES += tst_qscriptvalue.cpp + diff --git a/JavaScriptCore/qt/benchmarks/qscriptvalue/tst_qscriptvalue.cpp b/JavaScriptCore/qt/benchmarks/qscriptvalue/tst_qscriptvalue.cpp new file mode 100644 index 0000000..7c39b8e --- /dev/null +++ b/JavaScriptCore/qt/benchmarks/qscriptvalue/tst_qscriptvalue.cpp @@ -0,0 +1,442 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "qscriptengine.h" +#include "qscriptstring.h" +#include "qscriptvalue.h" +#include <qtest.h> + +Q_DECLARE_METATYPE(QScriptValue); + +class tst_QScriptValue : public QObject { + Q_OBJECT + +public: + tst_QScriptValue() + : m_engine(0) + {} + + ~tst_QScriptValue() + { + if (m_engine) + delete m_engine; + } + +private slots: + void values_data(); + + void ctorBool(); + void ctorReal(); + void ctorNumber(); + void ctorQString(); + void ctorCString(); + void ctorSpecial(); + void ctorQScriptValue(); + + void isValid_data(); + void isValid(); + void isBool_data(); + void isBool(); + void isNumber_data(); + void isNumber(); + void isFunction_data(); + void isFunction(); + void isNull_data(); + void isNull(); + void isString_data(); + void isString(); + void isUndefined_data(); + void isUndefined(); + void isObject_data(); + void isObject(); + void isError_data(); + void isError(); + + void toString_data(); + void toString(); + void toNumber_data(); + void toNumber(); + void toBool_data(); + void toBool(); + void toInteger_data(); + void toInteger(); + void toInt32_data(); + void toInt32(); + void toUInt32_data(); + void toUInt32(); + void toUInt16_data(); + void toUInt16(); + void toObject_data(); + void toObject(); + + void equals_data(); + void equals(); + void strictlyEquals_data(); + void strictlyEquals(); + void instanceOf_data(); + void instanceOf(); + +private: + QScriptEngine* m_engine; +}; + +void tst_QScriptValue::values_data() +{ + if (m_engine) + delete m_engine; + m_engine = new QScriptEngine; + + QTest::addColumn<QScriptValue>("value"); + + QTest::newRow("invalid") << QScriptValue(); + + QTest::newRow("cbool") << QScriptValue(true); + QTest::newRow("cnumber") << QScriptValue(1234); + QTest::newRow("cstring") << QScriptValue("abc"); + QTest::newRow("cnull") << QScriptValue(QScriptValue::NullValue); + QTest::newRow("cundefined") << QScriptValue(QScriptValue::UndefinedValue); + + QTest::newRow("jsbool") << m_engine->evaluate("true"); + QTest::newRow("jsnumber") << m_engine->evaluate("12345"); + QTest::newRow("jsstring") << m_engine->evaluate("'go'"); + QTest::newRow("jsfunction") << m_engine->evaluate("(function {})"); + QTest::newRow("jsnull") << m_engine->nullValue(); + QTest::newRow("jsundefined") << m_engine->undefinedValue(); + QTest::newRow("jsobject") << m_engine->newObject(); + QTest::newRow("jserror") << m_engine->evaluate("new Error()"); +} + +void tst_QScriptValue::ctorBool() +{ + QBENCHMARK { + QScriptValue(true); + } +} + +void tst_QScriptValue::ctorReal() +{ + QBENCHMARK { + QScriptValue(12.3); + } +} + +void tst_QScriptValue::ctorNumber() +{ + QBENCHMARK { + QScriptValue(123); + } +} + +void tst_QScriptValue::ctorQString() +{ + QString str = QString::fromLatin1("ciao"); + QBENCHMARK { + QScriptValue(str); + } +} + +void tst_QScriptValue::ctorCString() +{ + QBENCHMARK { + QScriptValue("Pong!"); + } +} + +void tst_QScriptValue::ctorSpecial() +{ + QBENCHMARK { + (void)QScriptValue(QScriptValue::NullValue); + } +} + +void tst_QScriptValue::ctorQScriptValue() +{ + QScriptValue tmp(1234); + QBENCHMARK { + QScriptValue(tmp); + } +} + +void tst_QScriptValue::isValid_data() +{ + values_data(); +} + +void tst_QScriptValue::isValid() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isValid(); + } +} + +void tst_QScriptValue::isBool_data() +{ + values_data(); +} + +void tst_QScriptValue::isBool() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isBool(); + } +} + +void tst_QScriptValue::isNumber_data() +{ + values_data(); +} + +void tst_QScriptValue::isNumber() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isNumber(); + } +} + +void tst_QScriptValue::isFunction_data() +{ + values_data(); +} + +void tst_QScriptValue::isFunction() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isFunction(); + } +} + +void tst_QScriptValue::isNull_data() +{ + values_data(); +} + +void tst_QScriptValue::isNull() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isNull(); + } +} + +void tst_QScriptValue::isString_data() +{ + values_data(); +} + +void tst_QScriptValue::isString() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isString(); + } +} + +void tst_QScriptValue::isUndefined_data() +{ + values_data(); +} + +void tst_QScriptValue::isUndefined() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isUndefined(); + } +} + +void tst_QScriptValue::isObject_data() +{ + values_data(); +} + +void tst_QScriptValue::isObject() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isObject(); + } +} + +void tst_QScriptValue::isError_data() +{ + values_data(); +} + +void tst_QScriptValue::isError() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.isError(); + } +} + +void tst_QScriptValue::toString_data() +{ + values_data(); +} + +void tst_QScriptValue::toString() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toString(); + } +} + +void tst_QScriptValue::toNumber_data() +{ + values_data(); +} + +void tst_QScriptValue::toNumber() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toNumber(); + } +} + +void tst_QScriptValue::toBool_data() +{ + values_data(); +} + +void tst_QScriptValue::toBool() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toBool(); + } +} + +void tst_QScriptValue::toInteger_data() +{ + values_data(); +} + +void tst_QScriptValue::toInteger() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toInteger(); + } +} + +void tst_QScriptValue::toInt32_data() +{ + values_data(); +} + +void tst_QScriptValue::toInt32() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toInt32(); + } +} + +void tst_QScriptValue::toUInt32_data() +{ + values_data(); +} + +void tst_QScriptValue::toUInt32() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toUInt32(); + } +} + +void tst_QScriptValue::toUInt16_data() +{ + values_data(); +} + +void tst_QScriptValue::toUInt16() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toUInt16(); + } +} + +void tst_QScriptValue::toObject_data() +{ + values_data(); +} + +void tst_QScriptValue::toObject() +{ + QFETCH(QScriptValue, value); + QBENCHMARK { + value.toObject(); + } +} + +void tst_QScriptValue::equals_data() +{ + values_data(); +} + +void tst_QScriptValue::equals() +{ + QFETCH(QScriptValue, value); + static QScriptValue previous; + QBENCHMARK { + value.equals(previous); + } + previous = value; +} + +void tst_QScriptValue::strictlyEquals_data() +{ + values_data(); +} + +void tst_QScriptValue::strictlyEquals() +{ + QFETCH(QScriptValue, value); + static QScriptValue previous; + QBENCHMARK { + value.strictlyEquals(previous); + } + previous = value; +} + +void tst_QScriptValue::instanceOf_data() +{ + values_data(); +} + +void tst_QScriptValue::instanceOf() +{ + QFETCH(QScriptValue, value); + static QScriptValue object = m_engine->newObject(); + QBENCHMARK { + value.instanceOf(object); + } +} + +QTEST_MAIN(tst_QScriptValue) +#include "tst_qscriptvalue.moc" diff --git a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp index d545f37..753fcd0 100644 --- a/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp +++ b/JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp @@ -47,6 +47,8 @@ private slots: void checkSyntax(); void toObject(); void toObjectTwoEngines(); + void newArray(); + void uncaughtException(); }; /* Evaluating a script that throw an unhandled exception should return an invalid value. */ @@ -409,5 +411,107 @@ void tst_QScriptEngine::toObjectTwoEngines() } } +void tst_QScriptEngine::newArray() +{ + QScriptEngine eng; + QScriptValue array = eng.newArray(); + QCOMPARE(array.isValid(), true); + // QCOMPARE(array.isArray(), true); + QCOMPARE(array.isObject(), true); + QVERIFY(!array.isFunction()); + // QCOMPARE(array.scriptClass(), (QScriptClass*)0); + + // Prototype should be Array.prototype. + QCOMPARE(array.prototype().isValid(), true); + // QCOMPARE(array.prototype().isArray(), true); + QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true); + + QScriptValue arrayWithSize = eng.newArray(42); + QCOMPARE(arrayWithSize.isValid(), true); + // QCOMPARE(arrayWithSize.isArray(), true); + QCOMPARE(arrayWithSize.isObject(), true); + QCOMPARE(arrayWithSize.property("length").toInt32(), 42); +} + +void tst_QScriptEngine::uncaughtException() +{ + QScriptEngine eng; + QScriptValue fun = eng.evaluate("(function foo () { return null; });"); + QVERIFY(!eng.uncaughtException().isValid()); + QVERIFY(fun.isFunction()); + QScriptValue throwFun = eng.evaluate("( function() { throw new Error('Pong'); });"); + QVERIFY(throwFun.isFunction()); + { + eng.evaluate("a = 10"); + QVERIFY(!eng.hasUncaughtException()); + QVERIFY(!eng.uncaughtException().isValid()); + } + { + eng.evaluate("1 = 2"); + QVERIFY(eng.hasUncaughtException()); + eng.clearExceptions(); + QVERIFY(!eng.hasUncaughtException()); + } + { + // Check if the call or toString functions can remove the last exception. + QVERIFY(throwFun.call().isError()); + QVERIFY(eng.hasUncaughtException()); + QScriptValue exception = eng.uncaughtException(); + fun.call(); + exception.toString(); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(eng.uncaughtException().strictlyEquals(exception)); + } + eng.clearExceptions(); + { + // Check if in the call function a new exception can override an existing one. + throwFun.call(); + QVERIFY(eng.hasUncaughtException()); + QScriptValue exception = eng.uncaughtException(); + throwFun.call(); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(!exception.strictlyEquals(eng.uncaughtException())); + } + { + eng.evaluate("throwFun = (function foo () { throw new Error('bla') });"); + eng.evaluate("1;\nthrowFun();"); + QVERIFY(eng.hasUncaughtException()); + QCOMPARE(eng.uncaughtExceptionLineNumber(), 1); + eng.clearExceptions(); + QVERIFY(!eng.hasUncaughtException()); + } + for (int x = 1; x < 4; ++x) { + QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", + QString::fromLatin1("FooScript") + QString::number(x), + /* lineNumber */ x); + QVERIFY(eng.hasUncaughtException()); + QCOMPARE(eng.uncaughtExceptionLineNumber(), x + 2); + QVERIFY(eng.uncaughtException().strictlyEquals(ret)); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(eng.uncaughtException().strictlyEquals(ret)); + QString backtrace = QString::fromLatin1("<anonymous>()@FooScript") + QString::number(x) + ":" + QString::number(x + 2); + QCOMPARE(eng.uncaughtExceptionBacktrace().join(""), backtrace); + QVERIFY(fun.call().isNull()); + QVERIFY(eng.hasUncaughtException()); + QCOMPARE(eng.uncaughtExceptionLineNumber(), x + 2); + QVERIFY(eng.uncaughtException().strictlyEquals(ret)); + eng.clearExceptions(); + QVERIFY(!eng.hasUncaughtException()); + QCOMPARE(eng.uncaughtExceptionLineNumber(), -1); + QVERIFY(!eng.uncaughtException().isValid()); + eng.evaluate("2 = 3"); + QVERIFY(eng.hasUncaughtException()); + QScriptValue ret2 = throwFun.call(); + QVERIFY(ret2.isError()); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(eng.uncaughtException().strictlyEquals(ret2)); + QCOMPARE(eng.uncaughtExceptionLineNumber(), 1); + eng.clearExceptions(); + QVERIFY(!eng.hasUncaughtException()); + eng.evaluate("1 + 2"); + QVERIFY(!eng.hasUncaughtException()); + } +} + QTEST_MAIN(tst_QScriptEngine) #include "tst_qscriptengine.moc" diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp index 27d6df2..2a2a6b1 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp @@ -580,4 +580,17 @@ void tst_QScriptValue::toObjectSimple() } } +void tst_QScriptValue::propertySimple() +{ + QScriptEngine eng; + + QScriptValue simpleObject(eng.evaluate("new Object({ test: 1, other: 2 })")); + QCOMPARE(simpleObject.property("test").toUInt32(), quint32(1)); + QCOMPARE(simpleObject.property("other").toUInt32(), quint32(2)); + + QScriptValue simpleArray(eng.evaluate("new Array(7, 8, 9)")); + QCOMPARE(simpleArray.property("length").toUInt32(), quint32(3)); + QCOMPARE(simpleArray.property(2).toUInt32(), quint32(9)); +} + QTEST_MAIN(tst_QScriptValue) diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h index f9fcedb..af600a6 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h @@ -51,6 +51,7 @@ private slots: void call(); void ctor(); void toObjectSimple(); + void propertySimple(); // Generated test functions. void isBool_data(); |