diff options
author | Kristian Monsen <kristianm@google.com> | 2010-06-28 16:42:48 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2010-07-02 10:29:56 +0100 |
commit | 06ea8e899e48f1f2f396b70e63fae369f2f23232 (patch) | |
tree | 20c1428cd05c76f32394ab354ea35ed99acd86d8 /JavaScriptCore/qt | |
parent | 72aad67af14193199e29cdd5c4ddc095a8b9a8a8 (diff) | |
download | external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.zip external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.gz external_webkit-06ea8e899e48f1f2f396b70e63fae369f2f23232.tar.bz2 |
Merge WebKit at r61871: Initial merge by git.
Change-Id: I6cff43abca9cc4782e088a469ad4f03f166a65d5
Diffstat (limited to 'JavaScriptCore/qt')
-rw-r--r-- | JavaScriptCore/qt/api/qscriptengine_p.cpp | 2 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue.cpp | 28 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue.h | 4 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue_p.h | 193 | ||||
-rw-r--r-- | JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp | 40 | ||||
-rw-r--r-- | JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h | 1 |
6 files changed, 186 insertions, 82 deletions
diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp index a6cf4a4..fd7978b 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.cpp +++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp @@ -85,5 +85,5 @@ QScriptValuePrivate* QScriptEnginePrivate::newObject() const QScriptValuePrivate* QScriptEnginePrivate::globalObject() const { JSObjectRef globalObject = JSContextGetGlobalObject(m_context); - return new QScriptValuePrivate(this, globalObject, globalObject); + return new QScriptValuePrivate(this, globalObject); } diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index 22ff8be..8ad76a5 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -518,6 +518,34 @@ QScriptEngine* QScriptValue::engine() const } /*! + If this QScriptValue is an object, returns the internal prototype + (\c{__proto__} property) of this object; otherwise returns an + invalid QScriptValue. + + \sa setPrototype(), isObject() +*/ +QScriptValue QScriptValue::prototype() const +{ + return QScriptValuePrivate::get(d_ptr->prototype()); +} + +/*! + If this QScriptValue is an object, sets the internal prototype + (\c{__proto__} property) of this object to be \a prototype; + otherwise does nothing. + + The internal prototype should not be confused with the public + property with name "prototype"; the public prototype is usually + only set on functions that act as constructors. + + \sa prototype(), isObject() +*/ +void QScriptValue::setPrototype(const QScriptValue& prototype) +{ + d_ptr->setPrototype(QScriptValuePrivate::get(prototype)); +} + +/*! Assigns the \a other value to this QScriptValue. Note that if \a other is an object (isObject() returns true), diff --git a/JavaScriptCore/qt/api/qscriptvalue.h b/JavaScriptCore/qt/api/qscriptvalue.h index 6c42429..c82ef55 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.h +++ b/JavaScriptCore/qt/api/qscriptvalue.h @@ -59,6 +59,10 @@ public: ~QScriptValue(); QScriptValue& operator=(const QScriptValue& other); + + QScriptValue prototype() const; + void setPrototype(const QScriptValue& prototype); + bool equals(const QScriptValue& other) const; bool strictlyEquals(const QScriptValue& other) const; bool instanceOf(const QScriptValue& other) const; diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index 1bb8a77..f8a1e7a 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -25,6 +25,7 @@ #include "qscriptvalue.h" #include <JavaScriptCore/JavaScript.h> #include <JavaScriptCore/JSRetainPtr.h> +#include <JSObjectRefPrivate.h> #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> #include <QtCore/qshareddata.h> @@ -49,7 +50,7 @@ class QScriptValue; CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current value is kept in m_number CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept - in m_number + in m_bool CNull -> QSVP is null, but a JSC engine hasn't been associated yet. CUndefined -> QSVP is undefined, but a JSC engine hasn't been associated yet. JSValue -> QSVP is associated with engine, but there is no information about real type, the state @@ -89,7 +90,7 @@ public: inline QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value); inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object); inline bool isValid() const; inline bool isBool(); @@ -108,8 +109,11 @@ public: inline qint32 toInt32() const; inline quint32 toUInt32() const; inline quint16 toUInt16() const; + inline QScriptValuePrivate* toObject(QScriptEnginePrivate* engine); inline QScriptValuePrivate* toObject(); + inline QScriptValuePrivate* prototype(); + inline void setPrototype(QScriptValuePrivate* prototype); inline bool equals(QScriptValuePrivate* other); inline bool strictlyEquals(QScriptValuePrivate* other); @@ -137,12 +141,23 @@ private: JSObject } m_state; QScriptEnginePtr m_engine; - QString m_string; - qsreal m_number; - JSValueRef m_value; - JSObjectRef m_object; - - inline void setValue(JSValueRef); + union Value + { + bool m_bool; + qsreal m_number; + JSValueRef m_value; + JSObjectRef m_object; + QString* m_string; + + Value() : m_number(0) {} + Value(bool value) : m_bool(value) {} + Value(int number) : m_number(number) {} + Value(uint number) : m_number(number) {} + Value(qsreal number) : m_number(number) {} + Value(JSValueRef value) : m_value(value) {} + Value(JSObjectRef object) : m_object(object) {} + Value(QString* string) : m_string(string) {} + } u; inline bool inherits(const char*); inline State refinedJSValue(); @@ -166,131 +181,124 @@ QScriptValue QScriptValuePrivate::get(QScriptValuePrivate* d) QScriptValuePrivate::~QScriptValuePrivate() { - if (m_value) - JSValueUnprotect(*m_engine, m_value); + if (isJSBased()) + JSValueUnprotect(*m_engine, u.m_value); + else if (isStringBased()) + delete u.m_string; } QScriptValuePrivate::QScriptValuePrivate() : m_state(Invalid) - , m_value(0) { } QScriptValuePrivate::QScriptValuePrivate(const QString& string) : m_state(CString) - , m_string(string) - , m_value(0) + , u(new QString(string)) { } QScriptValuePrivate::QScriptValuePrivate(bool value) : m_state(CBool) - , m_number(value) - , m_value(0) + , u(value) { } QScriptValuePrivate::QScriptValuePrivate(int number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(uint number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(qsreal number) : m_state(CNumber) - , m_number(number) - , m_value(0) + , u(number) { } QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value) : m_state(value == QScriptValue::NullValue ? CNull : CUndefined) - , m_value(0) { } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(engine->makeJSValue(value)) + , u(engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, int value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value) : m_state(JSPrimitive) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(m_engine->makeJSValue(value)) + , u(m_engine->makeJSValue(value)) { Q_ASSERT(engine); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value) : m_state(JSValue) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(value) + , u(value) { Q_ASSERT(engine); Q_ASSERT(value); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, u.m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object) : m_state(JSObject) , m_engine(const_cast<QScriptEnginePrivate*>(engine)) - , m_value(value) - , m_object(object) + , u(object) { Q_ASSERT(engine); - Q_ASSERT(value); Q_ASSERT(object); - JSValueProtect(*m_engine, m_value); + JSValueProtect(*m_engine, object); } bool QScriptValuePrivate::isValid() const { return m_state != Invalid; } @@ -422,11 +430,11 @@ QString QScriptValuePrivate::toString() const case Invalid: return QString(); case CBool: - return m_number ? QString::fromLatin1("true") : QString::fromLatin1("false"); + return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false"); case CString: - return m_string; + return *u.m_string; case CNumber: - return QScriptConverter::toString(m_number); + return QScriptConverter::toString(u.m_number); case CNull: return QString::fromLatin1("null"); case CUndefined: @@ -450,9 +458,9 @@ qsreal QScriptValuePrivate::toNumber() const case JSObject: return JSValueToNumber(*m_engine, *this, /* exception */ 0); case CNumber: - return m_number; + return u.m_number; case CBool: - return m_number ? 1 : 0; + return u.m_bool ? 1 : 0; case CNull: case Invalid: return 0; @@ -460,15 +468,15 @@ qsreal QScriptValuePrivate::toNumber() const return qQNaN(); case CString: bool ok; - qsreal result = m_string.toDouble(&ok); + qsreal result = u.m_string->toDouble(&ok); if (ok) return result; - result = m_string.toInt(&ok, 0); // Try other bases. + result = u.m_string->toInt(&ok, 0); // Try other bases. if (ok) return result; - if (m_string == "Infinity" || m_string == "-Infinity") + if (*u.m_string == "Infinity" || *u.m_string == "-Infinity") return qInf(); - return m_string.length() ? qQNaN() : 0; + return u.m_string->length() ? qQNaN() : 0; } Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement."); @@ -484,15 +492,15 @@ bool QScriptValuePrivate::toBool() const case JSObject: return true; case CNumber: - return !(qIsNaN(m_number) || !m_number); + return !(qIsNaN(u.m_number) || !u.m_number); case CBool: - return m_number; + return u.m_bool; case Invalid: case CNull: case CUndefined: return false; case CString: - return m_string.length(); + return u.m_string->length(); } Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement."); @@ -551,23 +559,23 @@ QScriptValuePrivate* QScriptValuePrivate::toObject(QScriptEnginePrivate* engine) case CString: { // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(m_string), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(*u.m_string), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case CNumber: { // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(m_number), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_number), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case CBool: { // Exception can't occure here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(static_cast<bool>(m_number)), /* exception */ 0); + JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_bool), /* exception */ 0); Q_ASSERT(object); - return new QScriptValuePrivate(engine, object, object); + return new QScriptValuePrivate(engine, object); } case JSValue: if (refinedJSValue() != JSPrimitive) @@ -605,6 +613,35 @@ QScriptValuePrivate* QScriptValuePrivate::toObject() return new QScriptValuePrivate; } +inline QScriptValuePrivate* QScriptValuePrivate::prototype() +{ + if (isObject()) { + JSValueRef prototype = JSObjectGetPrototype(*m_engine, *this); + if (JSValueIsNull(*m_engine, 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; +} + +inline void QScriptValuePrivate::setPrototype(QScriptValuePrivate* prototype) +{ + if (isObject() && prototype->isValid() && (prototype->isObject() || prototype->isNull())) { + if (engine() != prototype->engine()) { + qWarning("QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine"); + return; + } + // FIXME: This could be replaced by a new, faster API + // look at https://bugs.webkit.org/show_bug.cgi?id=40060 + JSObjectSetPrototype(*m_engine, *this, *prototype); + JSValueRef proto = JSObjectGetPrototype(*m_engine, *this); + if (!JSValueIsStrictEqual(*m_engine, proto, *prototype)) + qWarning("QScriptValue::setPrototype() failed: cyclic prototype value"); + } +} + bool QScriptValuePrivate::equals(QScriptValuePrivate* other) { if (!isValid()) @@ -615,9 +652,9 @@ bool QScriptValuePrivate::equals(QScriptValuePrivate* other) if ((m_state == other->m_state) && !isJSBased()) { if (isNumberBased()) - return m_number == other->m_number; + return u.m_number == other->u.m_number; Q_ASSERT(isStringBased()); - return m_string == other->m_string; + return *u.m_string == *(other->u.m_string); } if (!isJSBased() && !other->isJSBased()) @@ -655,7 +692,7 @@ bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) } if (isStringBased()) { if (other->isStringBased()) - return m_string == other->m_string; + return *u.m_string == *(other->u.m_string); if (other->isJSBased()) { assignEngine(other->engine()); return JSValueIsStrictEqual(*m_engine, *this, *other); @@ -663,7 +700,7 @@ bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) } if (isNumberBased()) { if (other->isNumberBased()) - return m_number == other->m_number; + return u.m_number == other->u.m_number; if (other->isJSBased()) { assignEngine(other->engine()); return JSValueIsStrictEqual(*m_engine, *this, *other); @@ -690,13 +727,14 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) JSValueRef value; switch (m_state) { case CBool: - value = engine->makeJSValue(static_cast<bool>(m_number)); + value = engine->makeJSValue(u.m_bool); break; case CString: - value = engine->makeJSValue(m_string); + value = engine->makeJSValue(*u.m_string); + delete u.m_string; break; case CNumber: - value = engine->makeJSValue(m_number); + value = engine->makeJSValue(u.m_number); break; case CNull: value = engine->makeJSValue(QScriptValue::NullValue); @@ -713,7 +751,8 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) } m_engine = engine; m_state = JSPrimitive; - setValue(value); + u.m_value = value; + JSValueProtect(*m_engine, value); return true; } @@ -763,22 +802,15 @@ QScriptEnginePrivate* QScriptValuePrivate::engine() const QScriptValuePrivate::operator JSValueRef() const { Q_ASSERT(isJSBased()); - return m_value; + Q_ASSERT(u.m_value); + return u.m_value; } QScriptValuePrivate::operator JSObjectRef() const { Q_ASSERT(m_state == JSObject); - return m_object; -} - -void QScriptValuePrivate::setValue(JSValueRef value) -{ - if (m_value) - JSValueUnprotect(*m_engine, m_value); - if (value) - JSValueProtect(*m_engine, value); - m_value = value; + Q_ASSERT(u.m_object); + return u.m_object; } /*! @@ -806,10 +838,9 @@ QScriptValuePrivate::State QScriptValuePrivate::refinedJSValue() if (!JSValueIsObject(*m_engine, *this)) { m_state = JSPrimitive; } else { + // Difference between JSValueRef and JSObjectRef is only in their type, binarywise it is the same. + // As m_value and m_object are stored in the u union, it is enough to change the m_state only. m_state = JSObject; - // We are sure that value is an JSObject, so we can const_cast safely without - // calling JSC C API (JSValueToObject(*m_engine, *this, /* exceptions */ 0)). - m_object = const_cast<JSObjectRef>(m_value); } return m_state; } diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp index 90730c3..27d6df2 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp @@ -431,6 +431,46 @@ void tst_QScriptValue::call() QVERIFY(incr.call().isValid()); // Exception. } +void tst_QScriptValue::getSetPrototype() +{ + QScriptEngine engine; + QScriptValue object = engine.evaluate("new Object()"); + QScriptValue object2 = engine.evaluate("new Object()"); + object2.setPrototype(object); + QCOMPARE(object2.prototype().strictlyEquals(object), true); + + QScriptValue inv; + inv.setPrototype(object); + QCOMPARE(inv.prototype().isValid(), false); + + QScriptEngine otherEngine; + QScriptValue object3 = otherEngine.evaluate("new Object()"); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine"); + object2.setPrototype(object3); + QCOMPARE(object2.prototype().strictlyEquals(object), true); + + // cyclic prototypes + { + QScriptValue ret = engine.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); + QCOMPARE(ret.isError(), true); + QCOMPARE(ret.toString(), QLatin1String("Error: cyclic __proto__ value")); + } + { + QScriptValue ret = engine.evaluate("p.__proto__ = { }"); + QCOMPARE(ret.isError(), false); + } + + QScriptValue old = object.prototype(); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value"); + object.setPrototype(object); + QCOMPARE(object.prototype().strictlyEquals(old), true); + + object2.setPrototype(object); + QTest::ignoreMessage(QtWarningMsg, "QScriptValue::setPrototype() failed: cyclic prototype value"); + object.setPrototype(object2); + QCOMPARE(object.prototype().strictlyEquals(old), true); +} + void tst_QScriptValue::toObjectSimple() { QScriptEngine eng; diff --git a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h index 0565b6f..f9fcedb 100644 --- a/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h +++ b/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h @@ -47,6 +47,7 @@ private slots: void dataSharing(); void constructors_data(); void constructors(); + void getSetPrototype(); void call(); void ctor(); void toObjectSimple(); |