Changeset 63318 in webkit


Ignore:
Timestamp:
Jul 14, 2010 7:35:08 AM (14 years ago)
Author:
commit-queue@webkit.org
Message:

2010-07-14 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>

Reviewed by Kenneth Rohde Christiansen.

Introduce QScriptOriginalGlobalObject.

QtScript exposes more functionality than JSC C API. Sometimes it is
necessary to take a shortcut in implementation. Really often we have
to use a standard JS function. These function could be changed or
even deleted by a script, so a backup of a reference to an object is needed.

In them same time this is rather a workaround then real fix, so the code
should be separated and changed easily in future. It is why we need
the new internal class.

The patch fixes a few crashes.

[Qt] QScriptEngine should work correctly even after global object changes
https://bugs.webkit.org/show_bug.cgi?id=41839

  • api/QtScript.pro:
  • api/qscriptengine_p.cpp: (QScriptEnginePrivate::QScriptEnginePrivate): (QScriptEnginePrivate::~QScriptEnginePrivate):
  • api/qscriptengine_p.h: (QScriptEnginePrivate::isArray): (QScriptEnginePrivate::isError): (QScriptEnginePrivate::objectHasOwnProperty): (QScriptEnginePrivate::objectGetOwnPropertyNames):
  • api/qscriptoriginalglobalobject_p.h: Added. (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject): (QScriptOriginalGlobalObject::initializeMember): (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject): (QScriptOriginalGlobalObject::objectHasOwnProperty): (QScriptOriginalGlobalObject::objectGetOwnPropertyNames): (QScriptOriginalGlobalObject::isArray): (QScriptOriginalGlobalObject::isError): (QScriptOriginalGlobalObject::isType):
  • api/qscriptvalue_p.h: (QScriptValuePrivate::isError): (QScriptValuePrivate::hasOwnProperty):
  • api/qscriptvalueiterator_p.h: (QScriptValueIteratorPrivate::QScriptValueIteratorPrivate):
  • tests/qscriptvalue/tst_qscriptvalue.cpp: (tst_QScriptValue::globalObjectChanges):
  • tests/qscriptvalue/tst_qscriptvalue.h:
Location:
trunk/JavaScriptCore/qt
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/qt/ChangeLog

    r63233 r63318  
     12010-07-14  Jedrzej Nowacki  <jedrzej.nowacki@nokia.com>
     2
     3        Reviewed by Kenneth Rohde Christiansen.
     4
     5        Introduce QScriptOriginalGlobalObject.
     6
     7        QtScript exposes more functionality than JSC C API. Sometimes it is
     8        necessary to take a shortcut in implementation. Really often we have
     9        to use a standard JS function. These function could be changed or
     10        even deleted by a script, so a backup of a reference to an object is needed.
     11
     12        In them same time this is rather a workaround then real fix, so the code
     13        should be separated and changed easily in future. It is why we need
     14        the new internal class.
     15
     16        The patch fixes a few crashes.
     17
     18        [Qt] QScriptEngine should work correctly even after global object changes
     19        https://bugs.webkit.org/show_bug.cgi?id=41839
     20
     21        * api/QtScript.pro:
     22        * api/qscriptengine_p.cpp:
     23        (QScriptEnginePrivate::QScriptEnginePrivate):
     24        (QScriptEnginePrivate::~QScriptEnginePrivate):
     25        * api/qscriptengine_p.h:
     26        (QScriptEnginePrivate::isArray):
     27        (QScriptEnginePrivate::isError):
     28        (QScriptEnginePrivate::objectHasOwnProperty):
     29        (QScriptEnginePrivate::objectGetOwnPropertyNames):
     30        * api/qscriptoriginalglobalobject_p.h: Added.
     31        (QScriptOriginalGlobalObject::QScriptOriginalGlobalObject):
     32        (QScriptOriginalGlobalObject::initializeMember):
     33        (QScriptOriginalGlobalObject::~QScriptOriginalGlobalObject):
     34        (QScriptOriginalGlobalObject::objectHasOwnProperty):
     35        (QScriptOriginalGlobalObject::objectGetOwnPropertyNames):
     36        (QScriptOriginalGlobalObject::isArray):
     37        (QScriptOriginalGlobalObject::isError):
     38        (QScriptOriginalGlobalObject::isType):
     39        * api/qscriptvalue_p.h:
     40        (QScriptValuePrivate::isError):
     41        (QScriptValuePrivate::hasOwnProperty):
     42        * api/qscriptvalueiterator_p.h:
     43        (QScriptValueIteratorPrivate::QScriptValueIteratorPrivate):
     44        * tests/qscriptvalue/tst_qscriptvalue.cpp:
     45        (tst_QScriptValue::globalObjectChanges):
     46        * tests/qscriptvalue/tst_qscriptvalue.h:
     47
    1482010-07-13  Jedrzej Nowacki  <jedrzej.nowacki@nokia.com>
    249
  • trunk/JavaScriptCore/qt/api/QtScript.pro

    r63233 r63318  
    4343            $$PWD/qscriptprogram_p.h \
    4444            $$PWD/qscriptsyntaxcheckresult.h \
     45            $$PWD/qscriptoriginalglobalobject_p.h \
    4546
    4647
  • trunk/JavaScriptCore/qt/api/qscriptengine_p.cpp

    r62661 r63318  
    3333    , m_context(JSGlobalContextCreate(0))
    3434    , m_exception(0)
    35     , m_arrayConstructor(0)
    36     , m_arrayPrototype(0)
     35    , m_originalGlobalObject(m_context)
    3736{
    38     JSObjectRef globalObject = JSContextGetGlobalObject(m_context);
    39 
    40     // Save references to the Array constructor and prototype.
    41     JSRetainPtr<JSStringRef> arrayName(Adopt, JSStringCreateWithUTF8CString("Array"));
    42     JSValueRef arrayConstructor = JSObjectGetProperty(m_context, globalObject, arrayName.get(), /* exception */ 0);
    43     Q_ASSERT(JSValueIsObject(m_context, arrayConstructor));
    44     m_arrayConstructor = JSValueToObject(m_context, arrayConstructor, /* exception */ 0);
    45     JSValueProtect(m_context, m_arrayConstructor);
    46 
    47     // Note that this is not the [[Prototype]] internal property (which we could
    48     // get via JSObjectGetPrototype), but the Array.prototype, that will be set
    49     // as [[Prototype]] of Array instances.
    50     JSRetainPtr<JSStringRef> prototypeName(Adopt, JSStringCreateWithUTF8CString("prototype"));
    51     JSValueRef arrayPrototype = JSObjectGetProperty(m_context, m_arrayConstructor, prototypeName.get(), /* exception */ 0);
    52     Q_ASSERT(JSValueIsObject(m_context, arrayPrototype));
    53     m_arrayPrototype = arrayPrototype;
    54     JSValueProtect(m_context, m_arrayPrototype);
    5537}
    5638
    5739QScriptEnginePrivate::~QScriptEnginePrivate()
    5840{
    59     JSValueUnprotect(m_context, m_arrayConstructor);
    60     JSValueUnprotect(m_context, m_arrayPrototype);
    6141    if (m_exception)
    6242        JSValueUnprotect(m_context, m_exception);
  • trunk/JavaScriptCore/qt/api/qscriptengine_p.h

    r62661 r63318  
    2323#include "qscriptconverter_p.h"
    2424#include "qscriptengine.h"
     25#include "qscriptoriginalglobalobject_p.h"
    2526#include "qscriptstring_p.h"
    2627#include "qscriptsyntaxcheckresult_p.h"
     
    8081
    8182    inline bool isArray(JSValueRef value) const;
     83    inline bool isError(JSValueRef value) const;
     84    inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const;
     85    inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const;
    8286private:
    8387    QScriptEngine* q_ptr;
     
    8589    JSValueRef m_exception;
    8690
    87     JSObjectRef m_arrayConstructor;
    88     JSValueRef m_arrayPrototype;
     91    QScriptOriginalGlobalObject m_originalGlobalObject;
    8992};
    9093
     
    219222bool QScriptEnginePrivate::isArray(JSValueRef value) const
    220223{
    221     // JSC API doesn't export the [[Class]] information for the builtins. But we know that a value
    222     // is an array if it was created with the Array constructor or if it is the Array.prototype.
    223     return JSValueIsInstanceOfConstructor(m_context, value, m_arrayConstructor, /* exception */ 0) || JSValueIsStrictEqual(m_context, value, m_arrayPrototype);
     224    return m_originalGlobalObject.isArray(value);
     225}
     226
     227bool QScriptEnginePrivate::isError(JSValueRef value) const
     228{
     229    return m_originalGlobalObject.isError(value);
     230}
     231
     232inline bool QScriptEnginePrivate::objectHasOwnProperty(JSObjectRef object, JSStringRef property) const
     233{
     234    // FIXME We need a JSC C API function for this.
     235    return m_originalGlobalObject.objectHasOwnProperty(object, property);
     236}
     237
     238inline QVector<JSStringRef> QScriptEnginePrivate::objectGetOwnPropertyNames(JSObjectRef object) const
     239{
     240    // FIXME We can't use C API function JSObjectGetPropertyNames as it returns only enumerable properties.
     241    return m_originalGlobalObject.objectGetOwnPropertyNames(object);
    224242}
    225243
  • trunk/JavaScriptCore/qt/api/qscriptvalue_p.h

    r62921 r63318  
    185185    } u;
    186186
    187     inline bool inherits(const char*);
    188187    inline State refinedJSValue();
    189188
     
    417416        // Fall-through.
    418417    case JSObject:
    419         return inherits("Error");
     418        return m_engine->isError(*this);
    420419    default:
    421420        return false;
     
    869868{
    870869    Q_ASSERT(isObject());
    871     // FIXME it could be faster, but JSC C API doesn't expose needed functionality.
    872     JSRetainPtr<JSStringRef> hasOwnPropertyName(Adopt, JSStringCreateWithUTF8CString("hasOwnProperty"));
    873     JSValueRef exception = 0;
    874     JSValueRef hasOwnProperty = JSObjectGetProperty(*m_engine, *this, hasOwnPropertyName.get(), &exception);
    875     JSValueRef propertyName[] = { JSValueMakeString(*m_engine, property) };
    876     JSValueRef result = JSObjectCallAsFunction(*m_engine, const_cast<JSObjectRef>(hasOwnProperty), *this, 1, propertyName, &exception);
    877     return exception ? false : JSValueToBoolean(*m_engine, result);
     870    return m_engine->objectHasOwnProperty(*this, property);
    878871}
    879872
     
    11251118/*!
    11261119  \internal
    1127   Returns true if QSV is created from constructor with the given \a name, it has to be a
    1128   built-in type.
    1129 */
    1130 bool QScriptValuePrivate::inherits(const char* name)
    1131 {
    1132     Q_ASSERT(isJSBased());
    1133     JSObjectRef globalObject = JSContextGetGlobalObject(*m_engine);
    1134     JSStringRef errorAttrName = QScriptConverter::toString(name);
    1135     JSValueRef exception = 0;
    1136     JSValueRef error = JSObjectGetProperty(*m_engine, globalObject, errorAttrName, &exception);
    1137     JSStringRelease(errorAttrName);
    1138     bool result = JSValueIsInstanceOfConstructor(*m_engine, *this, JSValueToObject(*m_engine, error, &exception), &exception);
    1139     m_engine->setException(exception);
    1140     return result;
    1141 }
    1142 
    1143 /*!
    1144   \internal
    11451120  Refines the state of this QScriptValuePrivate. Returns the new state.
    11461121*/
  • trunk/JavaScriptCore/qt/api/qscriptvalueiterator_p.h

    r63233 r63318  
    6464    , m_idx(m_names)
    6565{
    66     // FIXME There is assumption that global object wasn't changed (bug 41839).
    67     // FIXME We can't use C API function JSObjectGetPropertyNames as it returns only enumerable properties.
    68     if (const_cast<QScriptValuePrivate*>(value)->isObject()) {
    69         static JSStringRef objectName = QScriptConverter::toString("Object");
    70         static JSStringRef getOwnPropertyNamesName = QScriptConverter::toString("getOwnPropertyNames");
    71 
    72         JSValueRef exception = 0;
    73         JSObjectRef globalObject = JSContextGetGlobalObject(*engine());
    74         Q_ASSERT(JSValueIsObject(*engine(), globalObject));
    75         JSValueRef objectConstructor = JSObjectGetProperty(*engine(), globalObject, objectName, &exception);
    76         Q_ASSERT(JSValueIsObject(*engine(), objectConstructor));
    77         Q_ASSERT(!exception);
    78         JSValueRef propertyNamesGetter = JSObjectGetProperty(*engine(), const_cast<JSObjectRef>(objectConstructor), getOwnPropertyNamesName, &exception);
    79         Q_ASSERT(JSValueIsObject(*engine(), propertyNamesGetter));
    80         Q_ASSERT(!exception);
    81 
    82         JSValueRef arguments[] = { *m_object };
    83         JSObjectRef propertyNames
    84                 = const_cast<JSObjectRef>(JSObjectCallAsFunction(*engine(),
    85                                                                 const_cast<JSObjectRef>(propertyNamesGetter),
    86                                                                 /* thisObject */ 0,
    87                                                                 /* argumentCount */ 1,
    88                                                                 arguments,
    89                                                                 &exception));
    90         Q_ASSERT(JSValueIsObject(*engine(), propertyNames));
    91         Q_ASSERT(!exception);
    92         static JSStringRef lengthName = QScriptConverter::toString("length");
    93         int count = JSValueToNumber(*engine(), JSObjectGetProperty(*engine(), propertyNames, lengthName, &exception), &exception);
    94 
    95         Q_ASSERT(!exception);
    96         m_names.reserve(count);
    97         for (int i = 0; i < count; ++i) {
    98             JSValueRef tmp = JSObjectGetPropertyAtIndex(*engine(), propertyNames, i, &exception);
    99             m_names.append(JSValueToStringCopy(*engine(), tmp, &exception));
    100             Q_ASSERT(!exception);
    101         }
     66    if (m_object->isObject()) {
     67        m_names = engine()->objectGetOwnPropertyNames(*m_object);
    10268        m_idx = m_names;
    10369    } else
  • trunk/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.cpp

    r62921 r63318  
    12621262}
    12631263
     1264void tst_QScriptValue::globalObjectChanges()
     1265{
     1266    // API functionality shouldn't depend on Global Object.
     1267    QScriptEngine engine;
     1268    QScriptValue array = engine.newArray();
     1269    QScriptValue error = engine.evaluate("new Error");
     1270    QScriptValue object = engine.newObject();
     1271
     1272    object.setProperty("foo", 512);
     1273
     1274    // Remove properties form global object.
     1275    engine.evaluate("delete Object; delete Error; delete Array;");
     1276
     1277    QVERIFY(array.isArray());
     1278    QVERIFY(error.isError());
     1279    QVERIFY(object.isObject());
     1280
     1281    QVERIFY(object.property("foo").isValid());
     1282    QVERIFY(object.property("foo", QScriptValue::ResolveLocal).isValid());
     1283    object.setProperty("foo", QScriptValue());
     1284    QVERIFY(!object.property("foo").isValid());
     1285    QVERIFY(!object.property("foo", QScriptValue::ResolveLocal).isValid());
     1286}
     1287
    12641288QTEST_MAIN(tst_QScriptValue)
  • trunk/JavaScriptCore/qt/tests/qscriptvalue/tst_qscriptvalue.h

    r62921 r63318  
    6161    void propertyFlag_data();
    6262    void propertyFlag();
     63    void globalObjectChanges();
    6364
    6465    // Generated test functions.
Note: See TracChangeset for help on using the changeset viewer.