From 65b4ce3c51283adb76dcb73cc654b06359b1ae00 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 21 Sep 2009 12:56:11 +0200 Subject: QtScript: Fix comparing QVariant and QObject. This add a hook inside JSC to be able to implement our own comparison function when comparing objects. Reviewed-by: Kent Hansen --- .../JavaScriptCore/runtime/JSObject.h | 3 ++ .../JavaScriptCore/runtime/Operations.h | 6 +++- src/script/bridge/qscriptobject.cpp | 14 ++++++++ src/script/bridge/qscriptobject_p.h | 4 +++ src/script/bridge/qscriptqobject.cpp | 12 +++++++ src/script/bridge/qscriptqobject_p.h | 2 ++ src/script/bridge/qscriptvariant.cpp | 8 +++++ src/script/bridge/qscriptvariant_p.h | 2 ++ tests/auto/qscriptvalue/tst_qscriptvalue.cpp | 42 ++++++++++++++++++++-- 9 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h index 15b7957..35f7832 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h @@ -189,6 +189,9 @@ namespace JSC { virtual bool isActivationObject() const { return false; } virtual bool isWatchdogException() const { return false; } virtual bool isNotAnObjectErrorStub() const { return false; } +#ifdef QT_BUILD_SCRIPT_LIB + virtual bool compareToObject(ExecState*, JSObject *other) { return other == this; } +#endif void allocatePropertyStorage(size_t oldSize, size_t newSize); void allocatePropertyStorageInline(size_t oldSize, size_t newSize); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h index acfc6c2..a0caff4 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h @@ -73,7 +73,11 @@ namespace JSC { if (v1.isObject()) { if (v2.isObject()) - return v1 == v2; + return v1 == v2 +#ifdef QT_BUILD_SCRIPT_LIB + || asObject(v1)->compareToObject(exec, asObject(v2)) +#endif + ; JSValue p1 = v1.toPrimitive(exec); if (exec->hadException()) return false; diff --git a/src/script/bridge/qscriptobject.cpp b/src/script/bridge/qscriptobject.cpp index d46765a..0807dc2 100644 --- a/src/script/bridge/qscriptobject.cpp +++ b/src/script/bridge/qscriptobject.cpp @@ -145,6 +145,15 @@ void QScriptObject::getPropertyNames(JSC::ExecState* exec, JSC::PropertyNameArra d->delegate->getPropertyNames(this, exec, propertyNames, listedAttributes); } +bool QScriptObject::compareToObject(JSC::ExecState* exec, JSC::JSObject *other) +{ + if (!d || !d->delegate) { + return JSC::JSObject::compareToObject(exec, other); + } + return d->delegate->compareToObject(this, exec, other); +} + + void QScriptObject::mark() { Q_ASSERT(!marked()); @@ -255,4 +264,9 @@ bool QScriptObjectDelegate::hasInstance(QScriptObject* object, JSC::ExecState* e return object->JSC::JSObject::hasInstance(exec, value, proto); } +bool QScriptObjectDelegate::compareToObject(QScriptObject* object, JSC::ExecState* exec, JSC::JSObject* o) +{ + return object->JSC::JSObject::compareToObject(exec, o); +} + QT_END_NAMESPACE diff --git a/src/script/bridge/qscriptobject_p.h b/src/script/bridge/qscriptobject_p.h index 8f4113f..8060914 100644 --- a/src/script/bridge/qscriptobject_p.h +++ b/src/script/bridge/qscriptobject_p.h @@ -108,6 +108,8 @@ public: QScriptObjectDelegate *delegate() const; void setDelegate(QScriptObjectDelegate *delegate); + virtual bool compareToObject(JSC::ExecState*, JSC::JSObject*); + protected: Data *d; }; @@ -151,6 +153,8 @@ public: virtual bool hasInstance(QScriptObject*, JSC::ExecState*, JSC::JSValue value, JSC::JSValue proto); + virtual bool compareToObject(QScriptObject*, JSC::ExecState*, JSC::JSObject*); + private: Q_DISABLE_COPY(QScriptObjectDelegate) }; diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index b7df781..236f899 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -1572,6 +1572,18 @@ void QObjectDelegate::mark(QScriptObject *object) QScriptObjectDelegate::mark(object); } +bool QObjectDelegate::compareToObject(QScriptObject *, JSC::ExecState *exec, JSC::JSObject *o2) +{ + if(!o2->inherits(&QScriptObject::info)) + return false; + QScriptObject *object = static_cast(o2); + QScriptObjectDelegate *delegate = object->delegate(); + if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject)) + return false; + return value() == static_cast(delegate)->value(); +} + + static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList &args) { diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index ef26c7d..72d066d 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -122,6 +122,8 @@ public: inline void setOptions(QScriptEngine::QObjectWrapOptions options) { data->options = options; } + virtual bool compareToObject(QScriptObject*, JSC::ExecState*, JSC::JSObject*); + protected: Data *data; }; diff --git a/src/script/bridge/qscriptvariant.cpp b/src/script/bridge/qscriptvariant.cpp index 583b61c..aa7ad94 100644 --- a/src/script/bridge/qscriptvariant.cpp +++ b/src/script/bridge/qscriptvariant.cpp @@ -148,6 +148,13 @@ static JSC::JSValue JSC_HOST_CALL variantProtoFuncToString(JSC::ExecState *exec, return JSC::jsString(exec, result); } +bool QVariantDelegate::compareToObject(QScriptObject *, JSC::ExecState *exec, JSC::JSObject *o2) +{ + const QVariant &variant1 = value(); + return variant1 == scriptEngineFromExec(exec)->scriptValueFromJSCValue(o2).toVariant(); +} + + QVariantPrototype::QVariantPrototype(JSC::ExecState* exec, WTF::PassRefPtr structure, JSC::Structure* prototypeFunctionStructure) : QScriptObject(structure) @@ -158,6 +165,7 @@ QVariantPrototype::QVariantPrototype(JSC::ExecState* exec, WTF::PassRefPtrpropertyNames().valueOf, variantProtoFuncValueOf), JSC::DontEnum); } + } // namespace QScript QT_END_NAMESPACE diff --git a/src/script/bridge/qscriptvariant_p.h b/src/script/bridge/qscriptvariant_p.h index 9325396..4ce0aa6 100644 --- a/src/script/bridge/qscriptvariant_p.h +++ b/src/script/bridge/qscriptvariant_p.h @@ -73,6 +73,8 @@ public: Type type() const; + bool compareToObject(QScriptObject*, JSC::ExecState*, JSC::JSObject*); + private: QVariant m_value; }; diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp index 92b7c90..742f765 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp @@ -2875,15 +2875,27 @@ void tst_QScriptValue::equals() QScriptValue qobj1 = eng.newQObject(this); QScriptValue qobj2 = eng.newQObject(this); + QScriptValue qobj3 = eng.newQObject(0); + QScriptValue qobj4 = eng.newQObject(new QObject()); QVERIFY(qobj1.equals(qobj2)); // compares the QObject pointers + QVERIFY(!qobj2.equals(qobj4)); // compares the QObject pointers + QVERIFY(!qobj2.equals(obj2)); // compares the QObject pointers QScriptValue compareFun = eng.evaluate("(function(a, b) { return a == b; })"); QVERIFY(compareFun.isFunction()); { QScriptValue ret = compareFun.call(QScriptValue(), QScriptValueList() << qobj1 << qobj2); QVERIFY(ret.isBool()); - QEXPECT_FAIL("", "In JSC back-end, == on QObject wrappers doesn't work", Continue); QVERIFY(ret.toBool()); + ret = compareFun.call(QScriptValue(), QScriptValueList() << qobj1 << qobj3); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + ret = compareFun.call(QScriptValue(), QScriptValueList() << qobj1 << qobj4); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + ret = compareFun.call(QScriptValue(), QScriptValueList() << qobj1 << obj1); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); } { @@ -2893,7 +2905,6 @@ void tst_QScriptValue::equals() { QScriptValue ret = compareFun.call(QScriptValue(), QScriptValueList() << var1 << var2); QVERIFY(ret.isBool()); - QEXPECT_FAIL("", "In JSC back-end, == on QVariant wrappers doesn't work", Continue); QVERIFY(ret.toBool()); } } @@ -2929,6 +2940,33 @@ void tst_QScriptValue::equals() // QVariant::operator==() performs type conversion QVERIFY(var1.equals(var2)); } + { + QScriptValue var1 = eng.newVariant(QVariant(QString::fromLatin1("123"))); + QScriptValue var2 = eng.newVariant(QVariant(double(123))); + QScriptValue var3(QString::fromLatin1("123")); + QScriptValue var4(123); + QScriptValue var4(123.0); + + QVERIFY(var1.equals(var1)); + QVERIFY(var1.equals(var2)); + QVERIFY(var1.equals(var3)); + QVERIFY(var1.equals(var4)); + + QVERIFY(var2.equals(var1)); + QVERIFY(var2.equals(var2)); + QVERIFY(var2.equals(var3)); + QVERIFY(var2.equals(var4)); + + QVERIFY(var3.equals(var1)); + QVERIFY(var3.equals(var2)); + QVERIFY(var3.equals(var3)); + QVERIFY(var3.equals(var4)); + + QVERIFY(var4.equals(var1)); + QVERIFY(var4.equals(var2)); + QVERIFY(var4.equals(var3)); + QVERIFY(var4.equals(var4)); + } QScriptEngine otherEngine; QTest::ignoreMessage(QtWarningMsg, "QScriptValue::equals: " -- cgit v0.12