Changeset 125428 in webkit


Ignore:
Timestamp:
Aug 13, 2012 10:53:33 AM (12 years ago)
Author:
Simon Hausmann
Message:

[Qt] Port meta method/signal/slot handling in run-time bridge to use JSC C API
https://bugs.webkit.org/show_bug.cgi?id=93476

Reviewed by Kenneth Rohde Christiansen.

Source/WebCore:

Based on patch by No'am Rosenthal and lots of good suggestions by Caio Marcelo.

Ported the code that mapped invokable methods (and signals/slots) as
well as the code that provides the connect() and disconnect() functions
over to use the JSC C API. In the process one behavioural change was
implemented: Previously meta methods were actually function objects
that through Function.prototype allowed calling via
object.method.call(object). Through the use of plain JS objects that is
not possible anymore.

If we tried to continue to use function objects (JSObjectMakeFunction)
then we would loose the ability to store the private pointer. An
alternative approach would be to use a regular object and install the
Function prototype (Function.prototype), but unfortunately we cannot do
that without loosing the common prototype for signals and slots.

  • bridge/qt/qt_class.cpp:

(JSC::Bindings::QtClass::fallbackObject):

  • bridge/qt/qt_instance.cpp:

(JSC::Bindings::QtInstance::~QtInstance):
(JSC::Bindings::QtInstance::newRuntimeObject):

  • bridge/qt/qt_instance.h:

(Bindings):
(QtInstance):

  • bridge/qt/qt_runtime.cpp:

(JSC::Bindings::prototypeForSignalsAndSlots):
(JSC::Bindings::QtRuntimeMethod::QtRuntimeMethod):
(JSC::Bindings::QtRuntimeMethod::~QtRuntimeMethod):
(JSC::Bindings::QtRuntimeMethod::call):
(JSC::Bindings::QtRuntimeMethod::connect):
(JSC::Bindings::QtRuntimeMethod::disconnect):
(JSC::Bindings::QtRuntimeMethod::jsObjectRef):
(JSC::Bindings::QtRuntimeMethod::connectOrDisconnect):
(Bindings):
(JSC::Bindings::QtConnectionObject::~QtConnectionObject):

  • bridge/qt/qt_runtime.h:

(JSC::Bindings::QtRuntimeMethod::name):
(QtRuntimeMethod):
(QtConnectionObject):

Source/WebKit/qt:

Changed semantics of some test expectations. Similarly to r125032 when generating
error exceptions for connect/disconnect, we cannot generate explicit type error
exceptions but only generic errors. Another change is that the meta-method wrapper
doesn't support the call() through Function.prototype anymore. See WebCore changelog
for details.

  • tests/qobjectbridge/tst_qobjectbridge.cpp:

(tst_QObjectBridge::connectAndDisconnect):
(tst_QObjectBridge::objectDeleted):
(tst_QObjectBridge::introspectQtMethods):

Location:
trunk/Source
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r125427 r125428  
     12012-08-13  Simon Hausmann  <simon.hausmann@nokia.com>
     2
     3        [Qt] Port meta method/signal/slot handling in run-time bridge to use JSC C API
     4        https://bugs.webkit.org/show_bug.cgi?id=93476
     5
     6        Reviewed by Kenneth Rohde Christiansen.
     7
     8        Based on patch by No'am Rosenthal and lots of good suggestions by Caio Marcelo.
     9
     10        Ported the code that mapped invokable methods (and signals/slots) as
     11        well as the code that provides the connect() and disconnect() functions
     12        over to use the JSC C API. In the process one behavioural change was
     13        implemented: Previously meta methods were actually function objects
     14        that through Function.prototype allowed calling via
     15        object.method.call(object). Through the use of plain JS objects that is
     16        not possible anymore.
     17
     18        If we tried to continue to use function objects (JSObjectMakeFunction)
     19        then we would loose the ability to store the private pointer. An
     20        alternative approach would be to use a regular object and install the
     21        Function prototype (Function.prototype), but unfortunately we cannot do
     22        that without loosing the common prototype for signals and slots.
     23
     24        * bridge/qt/qt_class.cpp:
     25        (JSC::Bindings::QtClass::fallbackObject):
     26        * bridge/qt/qt_instance.cpp:
     27        (JSC::Bindings::QtInstance::~QtInstance):
     28        (JSC::Bindings::QtInstance::newRuntimeObject):
     29        * bridge/qt/qt_instance.h:
     30        (Bindings):
     31        (QtInstance):
     32        * bridge/qt/qt_runtime.cpp:
     33        (JSC::Bindings::prototypeForSignalsAndSlots):
     34        (JSC::Bindings::QtRuntimeMethod::QtRuntimeMethod):
     35        (JSC::Bindings::QtRuntimeMethod::~QtRuntimeMethod):
     36        (JSC::Bindings::QtRuntimeMethod::call):
     37        (JSC::Bindings::QtRuntimeMethod::connect):
     38        (JSC::Bindings::QtRuntimeMethod::disconnect):
     39        (JSC::Bindings::QtRuntimeMethod::jsObjectRef):
     40        (JSC::Bindings::QtRuntimeMethod::connectOrDisconnect):
     41        (Bindings):
     42        (JSC::Bindings::QtConnectionObject::~QtConnectionObject):
     43        * bridge/qt/qt_runtime.h:
     44        (JSC::Bindings::QtRuntimeMethod::name):
     45        (QtRuntimeMethod):
     46        (QtConnectionObject):
     47
    1482012-08-13  Leandro Gracia Gil  <leandrogracia@chromium.org>
    249
  • trunk/Source/WebCore/bridge/qt/qt_class.cpp

    r124879 r125428  
    2121#include "qt_class.h"
    2222
     23#include "APICast.h"
    2324#include "Identifier.h"
    2425#include "qt_instance.h"
     
    7071{
    7172    QtInstance* qtinst = static_cast<QtInstance*>(inst);
     73    JSContextRef context = toRef(exec);
     74    JSValueRef* exception = 0;
    7275
    7376    UString ustring(identifier.publicName());
     
    7578
    7679    // First see if we have a cache hit
    77     JSObject* val = qtinst->m_methods.value(name).get();
    78     if (val)
    79         return val;
     80    if (QtRuntimeMethod* method = qtinst->m_methods.value(name))
     81        return toJS(method->jsObjectRef(context, exception));
    8082
    8183    // Nope, create an entry
     
    8486    // See if there is an exact match
    8587    int index = -1;
     88    QMetaMethod metaMethod;
    8689    if (normal.contains('(') && (index = m_metaObject->indexOfMethod(normal)) != -1) {
    87         QMetaMethod m = m_metaObject->method(index);
    88         if (m.access() != QMetaMethod::Private) {
    89             QtRuntimeMetaMethod* val = QtRuntimeMetaMethod::create(exec, ustring, static_cast<QtInstance*>(inst), index, normal, false);
    90             qtinst->m_methods.insert(name, val);
    91             return val;
    92         }
     90        metaMethod = m_metaObject->method(index);
     91        if (metaMethod.access() == QMetaMethod::Private)
     92            index = -1;
    9393    }
    9494
    9595    // Nope.. try a basename match
    96     const int count = m_metaObject->methodCount();
    97     for (index = count - 1; index >= 0; --index) {
    98         const QMetaMethod m = m_metaObject->method(index);
    99         if (m.access() == QMetaMethod::Private)
    100             continue;
    101 
    102         if (normal == m.name()) {
    103             QtRuntimeMetaMethod* val = QtRuntimeMetaMethod::create(exec, ustring, static_cast<QtInstance*>(inst), index, normal, false);
    104             qtinst->m_methods.insert(name, val);
    105             return val;
    106         }
    107     }
    108 
    109     return jsUndefined();
     96    if (index == -1) {
     97        const int count = m_metaObject->methodCount();
     98        for (index = count - 1; index >= 0; --index) {
     99            metaMethod = m_metaObject->method(index);
     100            if (metaMethod.access() == QMetaMethod::Private)
     101                continue;
     102
     103            if (metaMethod.name() == normal)
     104                break;
     105        }
     106    }
     107
     108    if (index == -1)
     109        return jsUndefined();
     110
     111    int flags = metaMethod.methodType() == QMetaMethod::Signal ? QtRuntimeMethod::MethodIsSignal : 0;
     112    QtRuntimeMethod* method = new QtRuntimeMethod(context, exception, static_cast<QtInstance*>(inst)->getObject(), normal, index, flags, qtinst);
     113    qtinst->m_methods.insert(name, method);
     114    return toJS(method->jsObjectRef(context, exception));
    110115}
    111116
  • trunk/Source/WebCore/bridge/qt/qt_instance.cpp

    r125253 r125428  
    9595    cachedInstances.remove(m_hashkey);
    9696
    97     // clean up (unprotect from gc) the JSValues we've created
     97    qDeleteAll(m_methods);
    9898    m_methods.clear();
    9999
     
    148148}
    149149
    150 void QtInstance::removeUnusedMethods()
    151 {
    152     for (QHash<QByteArray, QtWeakObjectReference>::Iterator it = m_methods.begin(), end = m_methods.end(); it != end; ) {
    153         if (!it.value().get())
    154             it = m_methods.erase(it);
    155         else
    156             ++it;
    157     }
    158 }
    159 
    160150QtInstance* QtInstance::getInstance(JSObject* object)
    161151{
     
    180170{
    181171    JSLockHolder lock(exec);
     172    qDeleteAll(m_methods);
    182173    m_methods.clear();
    183174    return QtRuntimeObject::create(exec, exec->lexicalGlobalObject(), this);
  • trunk/Source/WebCore/bridge/qt/qt_instance.h

    r125355 r125428  
    3434class QtClass;
    3535class QtField;
    36 class QtRuntimeMetaMethod;
     36class QtRuntimeMethod;
    3737
    3838class QtInstance : public Instance {
     
    7272    virtual void put(JSObject*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
    7373
    74     void removeUnusedMethods();
    75 
    7674    static QtInstance* getInstance(JSObject*);
    7775
    7876private:
    79 
    80     class QtWeakObjectReference {
    81     public:
    82         QtWeakObjectReference(JSObject* reference)
    83             : m_reference(reference)
    84         {
    85         }
    86 
    87         QtWeakObjectReference(const QtWeakObjectReference& source)
    88             : m_reference(source.m_reference.get())
    89         {
    90         }
    91 
    92         QtWeakObjectReference()
    93             : m_reference()
    94         {
    95         }
    96 
    97         QtWeakObjectReference& operator=(const QtWeakObjectReference& source)
    98         {
    99             m_reference = PassWeak<JSObject>(source.m_reference.get());
    100             return *this;
    101         }
    102 
    103         JSObject* get() const
    104         {
    105             return m_reference.get();
    106         }
    107 
    108     private:
    109         Weak<JSObject> m_reference;
    110     };
    111 
    11277    static PassRefPtr<QtInstance> create(QObject *instance, PassRefPtr<RootObject> rootObject, ValueOwnership ownership)
    11378    {
     
    12186    QPointer<QObject> m_object;
    12287    QObject* m_hashkey;
    123     mutable QHash<QByteArray, QtWeakObjectReference> m_methods;
     88    mutable QHash<QByteArray, QtRuntimeMethod*> m_methods;
    12489    mutable QHash<QString, QtField*> m_fields;
    12590    ValueOwnership m_ownership;
  • trunk/Source/WebCore/bridge/qt/qt_runtime.cpp

    r125276 r125428  
    914914}
    915915
    916 // ===============
    917 
    918 // Qt-like macros
    919 #define QW_D(Class) Class##Data* d = d_func()
    920 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
    921 
    922 const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMethod) };
    923 
    924 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, Structure* structure, const UString& identifier)
    925     : InternalFunction(exec->lexicalGlobalObject(), structure)
    926     , d_ptr(dd)
    927 {
    928 }
    929 
    930 void QtRuntimeMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance)
    931 {
    932     Base::finishCreation(exec->globalData(), identifier);
    933     QW_D(QtRuntimeMethod);
    934     d->m_instance = instance;
    935     d->m_finalizer = PassWeak<QtRuntimeMethod>(this, d);
    936 }
    937 
    938 QtRuntimeMethod::~QtRuntimeMethod()
    939 {
    940     delete d_ptr;
    941 }
    942 
    943 void QtRuntimeMethod::destroy(JSCell* cell)
    944 {
    945     static_cast<QtRuntimeMethod*>(cell)->QtRuntimeMethod::~QtRuntimeMethod();
    946 }
    947 
    948 // ===============
    949 
    950 QtRuntimeMethodData::~QtRuntimeMethodData()
    951 {
    952 }
    953 
    954 void QtRuntimeMethodData::finalize(Handle<Unknown>, void*)
    955 {
    956     m_instance->removeUnusedMethods();
    957 }
    958 
    959 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
    960 {
    961 
    962 }
    963 
    964 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
    965 {
    966 
    967 }
    968 
    969 // ===============
    970 
    971916// Type conversion metadata (from QtScript originally)
    972917class QtMethodMatchType
     
    13361281}
    13371282
    1338 const ClassInfo QtRuntimeMetaMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeMetaMethod) };
    1339 
    1340 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, Structure* structure, const UString& identifier)
    1341     : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, structure, identifier)
    1342 {
    1343 }
    1344 
    1345 void QtRuntimeMetaMethod::finishCreation(ExecState* exec, const UString& identifier, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature, bool allowPrivate)
    1346 {
    1347     Base::finishCreation(exec, identifier, instance);
    1348     QW_D(QtRuntimeMetaMethod);
    1349     d->m_signature = signature;
    1350     d->m_index = index;
    1351     d->m_allowPrivate = allowPrivate;
    1352 }
    1353 
    1354 void QtRuntimeMetaMethod::visitChildren(JSCell* cell, SlotVisitor& visitor)
    1355 {
    1356     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
    1357     QtRuntimeMethod::visitChildren(thisObject, visitor);
    1358     QtRuntimeMetaMethodData* d = thisObject->d_func();
    1359     if (d->m_connect)
    1360         visitor.append(&d->m_connect);
    1361     if (d->m_disconnect)
    1362         visitor.append(&d->m_disconnect);
    1363 }
    1364 
    1365 EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
    1366 {
    1367     QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
    1368 
    1369     // We're limited to 10 args
    1370     if (exec->argumentCount() > 10)
    1371         return JSValue::encode(jsUndefined());
    1372 
    1373     // We have to pick a method that matches..
    1374     JSLockHolder lock(exec);
    1375 
    1376     QObject *obj = d->m_instance->getObject();
    1377     if (obj) {
    1378         const int argumentCount = static_cast<int>(exec->argumentCount());
    1379         Vector<JSValueRef, 10> args(argumentCount);
    1380         for (int i = 0; i < argumentCount; ++i)
    1381             args[i] = toRef(exec, exec->argument(i));
    1382 
    1383         QVarLengthArray<QVariant, 10> vargs;
    1384         void *qargs[11];
    1385 
    1386         int methodIndex;
    1387         JSValueRef exception = 0;
    1388         if ((methodIndex = findMethodIndex(toRef(exec), obj->metaObject(), d->m_signature, argumentCount, args.data(), d->m_allowPrivate, vargs, (void **)qargs, &exception)) != -1) {
    1389             if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
    1390                 return JSValue::encode(jsUndefined());
    1391 
    1392             if (vargs.size() > 0 && vargs[0].isValid())
    1393                 return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
    1394         }
    1395 
    1396         if (exception)
    1397             return throwVMError(exec, toJS(exec, exception));
     1283static JSClassRef prototypeForSignalsAndSlots()
     1284{
     1285    static JSClassDefinition classDef = {
     1286        0, 0, 0, 0, 0, 0,
     1287        0, 0, 0, 0, 0, 0, 0, QtRuntimeMethod::call, 0, 0, 0
     1288    };
     1289    static JSClassRef cls = JSClassCreate(&classDef);
     1290    return cls;
     1291}
     1292
     1293QtRuntimeMethod::QtRuntimeMethod(JSContextRef ctx, JSValueRef* exception, QObject* object, const QByteArray& identifier, int index, int flags, QtInstance* instance)
     1294    : m_object(object)
     1295    , m_identifier(identifier)
     1296    , m_index(index)
     1297    , m_flags(flags)
     1298    , m_instance(instance)
     1299{
     1300}
     1301
     1302QtRuntimeMethod::~QtRuntimeMethod()
     1303{
     1304    if (m_jsObject)
     1305        JSObjectSetPrivate(toRef(m_jsObject.get()), 0);
     1306}
     1307
     1308JSValueRef QtRuntimeMethod::call(JSContextRef context, JSObjectRef function, JSObjectRef /*thisObject*/, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     1309{
     1310    QtRuntimeMethod* d = reinterpret_cast<QtRuntimeMethod*>(JSObjectGetPrivate(function));
     1311    if (!d) {
     1312        setException(context, exception, QStringLiteral("cannot call function of deleted runtime method"));
     1313        return JSValueMakeUndefined(context);
     1314    }
     1315    QObject* obj = d->m_object;
     1316
     1317    if (!obj) {
     1318        setException(context, exception, QStringLiteral("cannot call function of deleted QObject"));
     1319        return JSValueMakeUndefined(context);
     1320    }
     1321
     1322    // Allow for maximum of 10 arguments and size stack arrays accordingly.
     1323    if (argumentCount > 10)
     1324        return JSValueMakeUndefined(context);
     1325
     1326    QVarLengthArray<QVariant, 10> vargs;
     1327    void* qargs[11];
     1328
     1329    int methodIndex = findMethodIndex(context, obj->metaObject(), d->m_identifier,  argumentCount, arguments,
     1330                                      (d->m_flags & AllowPrivate), vargs, (void **)qargs, exception);
     1331
     1332    if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
     1333        return JSValueMakeUndefined(context);
     1334
     1335    if (vargs.size() > 0 && vargs[0].isValid())
     1336        return toRef(toJS(context), convertQVariantToValue(toJS(context), d->m_instance->rootObject(), vargs[0]));
     1337
     1338    return JSValueMakeUndefined(context);
     1339}
     1340
     1341JSValueRef QtRuntimeMethod::connect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     1342{
     1343    return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, true);
     1344}
     1345
     1346JSValueRef QtRuntimeMethod::disconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     1347{
     1348    return connectOrDisconnect(context, function, thisObject, argumentCount, arguments, exception, false);
     1349}
     1350
     1351JSObjectRef QtRuntimeMethod::jsObjectRef(JSContextRef context, JSValueRef* exception)
     1352{
     1353    if (m_jsObject)
     1354        return toRef(m_jsObject.get());
     1355
     1356    static const JSClassDefinition classDefForConnect = {
     1357        0, 0, "connect", 0, 0, 0,
     1358        0, 0, 0, 0, 0, 0, 0, connect, 0, 0, 0
     1359    };
     1360
     1361    static const JSClassDefinition classDefForDisconnect = {
     1362        0, 0, "disconnect", 0, 0, 0,
     1363        0, 0, 0, 0, 0, 0, 0, disconnect, 0, 0, 0
     1364    };
     1365
     1366    static JSClassRef classRefConnect = JSClassCreate(&classDefForConnect);
     1367    static JSClassRef classRefDisconnect = JSClassCreate(&classDefForDisconnect);
     1368    bool isSignal = m_flags & MethodIsSignal;
     1369    JSObjectRef object = JSObjectMake(context, prototypeForSignalsAndSlots(), this);
     1370    JSObjectRef connectFunction = JSObjectMake(context, classRefConnect, this);
     1371    JSObjectRef disconnectFunction = JSObjectMake(context, classRefDisconnect, this);
     1372    JSPropertyAttributes attributes = kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete;
     1373
     1374    static JSStringRef connectStr = JSStringCreateWithUTF8CString("connect");
     1375    static JSStringRef disconnectStr = JSStringCreateWithUTF8CString("disconnect");
     1376    static JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
     1377    static JSStringRef nameStr = JSStringCreateWithUTF8CString("name");
     1378    JSRetainPtr<JSStringRef> actualNameStr(Adopt, JSStringCreateWithUTF8CString(m_identifier.constData()));
     1379
     1380    JSObjectSetProperty(context, connectFunction, lengthStr, JSValueMakeNumber(context, isSignal ? 1 : 0), attributes, exception);
     1381    JSObjectSetProperty(context, connectFunction, nameStr, JSValueMakeString(context, connectStr), attributes, exception);
     1382    JSObjectSetProperty(context, disconnectFunction, lengthStr, JSValueMakeNumber(context, isSignal ? 1 : 0), attributes, exception);
     1383    JSObjectSetProperty(context, disconnectFunction, nameStr, JSValueMakeString(context, disconnectStr), attributes, exception);
     1384
     1385    JSObjectSetProperty(context, object, connectStr, connectFunction, attributes, exception);
     1386    JSObjectSetProperty(context, object, disconnectStr, disconnectFunction, attributes, exception);
     1387    JSObjectSetProperty(context, object, lengthStr, JSValueMakeNumber(context, 0), attributes, exception);
     1388    JSObjectSetProperty(context, object, nameStr, JSValueMakeString(context, actualNameStr.get()), attributes, exception);
     1389
     1390    m_jsObject = PassWeak<JSObject>(toJS(object));
     1391    return object;
     1392}
     1393
     1394JSValueRef QtRuntimeMethod::connectOrDisconnect(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception, bool connect)
     1395{
     1396    QtRuntimeMethod* d = static_cast<QtRuntimeMethod*>(JSObjectGetPrivate(thisObject));
     1397    if (!d)
     1398        d = static_cast<QtRuntimeMethod*>(JSObjectGetPrivate(function));
     1399
     1400    QString functionName = connect ? QStringLiteral("connect") : QStringLiteral("disconnect");
     1401
     1402    if (!argumentCount) {
     1403        QString errorStr = QStringLiteral("QtMetaMethod.%1: no arguments given").arg(connect ?  QStringLiteral("connect") : QStringLiteral("disconnect"));
     1404        setException(context, exception, errorStr);
     1405        return JSValueMakeUndefined(context);
     1406    }
     1407
     1408    if ((!(d->m_flags & QtRuntimeMethod::MethodIsSignal))) {
     1409        setException(context, exception, QStringLiteral("QtMetaMethod.%3: %1::%2() is not a signal").arg(QString::fromUtf8(d->m_object.data()->metaObject()->className())).arg(QString::fromAscii(d->m_identifier)).arg(functionName));
     1410        return JSValueMakeUndefined(context);
     1411    }
     1412
     1413    QObject* sender = d->m_object.data();
     1414
     1415    if (!sender) {
     1416        setException(context, exception, QStringLiteral("cannot call function of deleted QObject"));
     1417        return JSValueMakeUndefined(context);
     1418    }
     1419
     1420    int signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_identifier);
     1421
     1422    JSObjectRef targetObject = 0;
     1423    JSObjectRef targetFunction = 0;
     1424
     1425    if (argumentCount == 1) {
     1426        if (!JSValueIsObject(context, arguments[0])) {
     1427            setException(context, exception, QStringLiteral("QtMetaMethod.%1: target is not a function").arg(functionName));
     1428            return JSValueMakeUndefined(context);
     1429        }
     1430        targetFunction = JSValueToObject(context, arguments[0], exception);
     1431
     1432        // object.signal.connect(someFunction);
     1433        if (JSObjectIsFunction(context, targetFunction)) {
     1434            if (JSValueIsObjectOfClass(context, targetFunction, prototypeForSignalsAndSlots())) {
     1435                // object.signal.connect(otherObject.slot);
     1436                if (QtRuntimeMethod* targetMethod = static_cast<QtRuntimeMethod*>(JSObjectGetPrivate(targetFunction)))
     1437                    targetObject = toRef(QtInstance::getQtInstance(targetMethod->m_object.data(), d->m_instance->rootObject(), QtInstance::QtOwnership)->createRuntimeObject(toJS(context)));
     1438            }
     1439        } else
     1440            targetFunction = 0;
    13981441    } else {
    1399         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
    1400     }
    1401 
    1402     // void functions return undefined
    1403     return JSValue::encode(jsUndefined());
    1404 }
    1405 
    1406 CallType QtRuntimeMetaMethod::getCallData(JSCell*, CallData& callData)
    1407 {
    1408     callData.native.function = call;
    1409     return CallTypeHost;
    1410 }
    1411 
    1412 bool QtRuntimeMetaMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    1413 {
    1414     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(cell);
    1415     if (propertyName == Identifier(exec, "connect")) {
    1416         slot.setCustom(thisObject, thisObject->connectGetter);
    1417         return true;
    1418     }
    1419     if (propertyName == Identifier(exec, "disconnect")) {
    1420         slot.setCustom(thisObject, thisObject->disconnectGetter);
    1421         return true;
    1422     }
    1423     if (propertyName == exec->propertyNames().length) {
    1424         slot.setCustom(thisObject, thisObject->lengthGetter);
    1425         return true;
    1426     }
    1427 
    1428     return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
    1429 }
    1430 
    1431 bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
    1432 {
    1433     QtRuntimeMetaMethod* thisObject = jsCast<QtRuntimeMetaMethod*>(object);
    1434     if (propertyName == Identifier(exec, "connect")) {
    1435         PropertySlot slot;
    1436         slot.setCustom(thisObject, connectGetter);
    1437         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
    1438         return true;
    1439     }
    1440 
    1441     if (propertyName == Identifier(exec, "disconnect")) {
    1442         PropertySlot slot;
    1443         slot.setCustom(thisObject, disconnectGetter);
    1444         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
    1445         return true;
    1446     }
    1447 
    1448     if (propertyName == exec->propertyNames().length) {
    1449         PropertySlot slot;
    1450         slot.setCustom(thisObject, lengthGetter);
    1451         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
    1452         return true;
    1453     }
    1454 
    1455     return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
    1456 }
    1457 
    1458 void QtRuntimeMetaMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    1459 {
    1460     if (mode == IncludeDontEnumProperties) {
    1461         propertyNames.add(Identifier(exec, "connect"));
    1462         propertyNames.add(Identifier(exec, "disconnect"));
    1463         propertyNames.add(exec->propertyNames().length);
    1464     }
    1465 
    1466     QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
    1467 }
    1468 
    1469 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, PropertyName)
    1470 {
    1471     // QtScript always returns 0
    1472     return jsNumber(0);
    1473 }
    1474 
    1475 JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
    1476 {
    1477     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
    1478     QW_DS(QtRuntimeMetaMethod, thisObj);
    1479 
    1480     if (!d->m_connect)
    1481         d->m_connect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.publicName(), true, d->m_instance, d->m_index, d->m_signature));
    1482     return d->m_connect.get();
    1483 }
    1484 
    1485 JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, PropertyName ident)
    1486 {
    1487     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
    1488     QW_DS(QtRuntimeMetaMethod, thisObj);
    1489 
    1490     if (!d->m_disconnect)
    1491         d->m_disconnect.set(exec->globalData(), thisObj, QtRuntimeConnectionMethod::create(exec, ident.publicName(), false, d->m_instance, d->m_index, d->m_signature));
    1492     return d->m_disconnect.get();
     1442        // object.signal.connect(object, someFunction);
     1443        targetObject = JSValueToObject(context, arguments[0], exception);
     1444        if (JSValueIsObject(context, arguments[1])) {
     1445            JSObjectRef obj = JSValueToObject(context, arguments[1], exception);
     1446            if (JSObjectIsFunction(context, obj))
     1447                targetFunction = obj;
     1448        }
     1449        if (!targetFunction) {
     1450            // Maybe the second argument is a string
     1451            JSValueRef conversionException = 0;
     1452            JSRetainPtr<JSStringRef> functionName(Adopt, JSValueToStringCopy(context, arguments[1], &conversionException));
     1453            if (functionName && !conversionException) {
     1454                JSValueRef functionProperty = JSObjectGetProperty(context, targetObject, functionName.get(), &conversionException);
     1455                if (!conversionException && functionProperty && JSValueIsObject(context, functionProperty)) {
     1456                    targetFunction = JSValueToObject(context, functionProperty, 0);
     1457                    if (!JSObjectIsFunction(context, targetFunction))
     1458                        targetFunction = 0;
     1459                }
     1460            }
     1461        }
     1462    }
     1463
     1464    // object.signal.connect(someObject);
     1465    if (!targetFunction) {
     1466        QString message = QStringLiteral("QtMetaMethod.%1: target is not a function");
     1467        if (connect)
     1468            message = message.arg(QStringLiteral("connect"));
     1469        else
     1470            message = message.arg(QStringLiteral("disconnect"));
     1471        setException(context, exception, message);
     1472        return JSValueMakeUndefined(context);
     1473    }
     1474
     1475    if (connect) {
     1476        // to connect, we need:
     1477        //  target object [from ctor]
     1478        //  target signal index etc. [from ctor]
     1479        //  receiver function [from arguments]
     1480        //  receiver this object [from arguments]
     1481
     1482        QtConnectionObject* conn = new QtConnectionObject(context, QtInstance::getQtInstance(sender, d->m_instance->rootObject(), QtInstance::QtOwnership), signalIndex, targetObject, targetFunction);
     1483        bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
     1484        if (!ok) {
     1485            delete conn;
     1486            QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
     1487                    .arg(QLatin1String(sender->metaObject()->className()))
     1488                    .arg(QLatin1String(d->m_identifier));
     1489            setException(context, exception, msg);
     1490            return JSValueMakeUndefined(context);
     1491        }
     1492
     1493        // Store connection
     1494        QtConnectionObject::connections.insert(sender, conn);
     1495
     1496        return JSValueMakeUndefined(context);
     1497    }
     1498
     1499    // Now to find our previous connection object.
     1500    QList<QtConnectionObject*> conns = QtConnectionObject::connections.values(sender);
     1501
     1502    foreach (QtConnectionObject* conn, conns) {
     1503        // Is this the right connection?
     1504        if (!conn->match(context, sender, signalIndex, targetObject, targetFunction))
     1505            continue;
     1506
     1507        // Yep, disconnect it
     1508        QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
     1509        delete conn; // this will also remove it from the map
     1510        return JSValueMakeUndefined(context);
     1511    }
     1512
     1513    QString msg = QStringLiteral("QtMetaMethod.disconnect: failed to disconnect from %1::%2()")
     1514            .arg(QLatin1String(sender->metaObject()->className()))
     1515            .arg(QLatin1String(d->m_identifier));
     1516
     1517    setException(context, exception, msg);
     1518    return JSValueMakeUndefined(context);
    14931519}
    14941520
    14951521// ===============
    14961522
    1497 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
    1498 
    1499 const ClassInfo QtRuntimeConnectionMethod::s_info = { "QtRuntimeMethod", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(QtRuntimeConnectionMethod) };
    1500 
    1501 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, Structure* structure, const UString& identifier)
    1502     : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, structure, identifier)
    1503 {
    1504 }
    1505 
    1506 void QtRuntimeConnectionMethod::finishCreation(ExecState* exec, const UString& identifier, bool isConnect, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature)
    1507 {
    1508     Base::finishCreation(exec, identifier, instance);
    1509     QW_D(QtRuntimeConnectionMethod);
    1510 
    1511     d->m_signature = signature;
    1512     d->m_index = index;
    1513     d->m_isConnect = isConnect;
    1514 }
    1515 
    1516 EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
    1517 {
    1518     QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
    1519 
    1520     JSLockHolder lock(exec);
    1521 
    1522     QObject* sender = d->m_instance->getObject();
    1523 
    1524     if (sender) {
    1525 
    1526         JSObject* thisObject = exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec);
    1527         JSObject* funcObject = 0;
    1528 
    1529         // QtScript checks signalness first, arguments second
    1530         int signalIndex = -1;
    1531 
    1532         // Make sure the initial index is a signal
    1533         QMetaMethod m = sender->metaObject()->method(d->m_index);
    1534         if (m.methodType() == QMetaMethod::Signal)
    1535             signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
    1536 
    1537         if (signalIndex != -1) {
    1538             if (exec->argumentCount() == 1) {
    1539                 funcObject = exec->argument(0).toObject(exec);
    1540                 CallData callData;
    1541                 if (funcObject->methodTable()->getCallData(funcObject, callData) == CallTypeNone) {
    1542                     if (d->m_isConnect)
    1543                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
    1544                     else
    1545                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
    1546                 }
    1547             } else if (exec->argumentCount() >= 2) {
    1548                 if (exec->argument(0).isObject()) {
    1549                     thisObject = exec->argument(0).toObject(exec);
    1550 
    1551                     // Get the actual function to call
    1552                     JSObject *asObj = exec->argument(1).toObject(exec);
    1553                     CallData callData;
    1554                     if (asObj->methodTable()->getCallData(asObj, callData) != CallTypeNone) {
    1555                         // Function version
    1556                         funcObject = asObj;
    1557                     } else {
    1558                         // Convert it to a string
    1559                         UString funcName = exec->argument(1).toString(exec)->value(exec);
    1560                         Identifier funcIdent(exec, funcName);
    1561 
    1562                         // ### DropAllLocks
    1563                         // This is resolved at this point in QtScript
    1564                         JSValue val = thisObject->get(exec, funcIdent);
    1565                         JSObject* asFuncObj = val.toObject(exec);
    1566 
    1567                         if (asFuncObj->methodTable()->getCallData(asFuncObj, callData) != CallTypeNone) {
    1568                             funcObject = asFuncObj;
    1569                         } else {
    1570                             if (d->m_isConnect)
    1571                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
    1572                             else
    1573                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
    1574                         }
    1575                     }
    1576                 } else {
    1577                     if (d->m_isConnect)
    1578                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
    1579                     else
    1580                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
    1581                 }
    1582             } else {
    1583                 if (d->m_isConnect)
    1584                     return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
    1585                 else
    1586                     return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
    1587             }
    1588 
    1589             if (d->m_isConnect) {
    1590                 // to connect, we need:
    1591                 //  target object [from ctor]
    1592                 //  target signal index etc. [from ctor]
    1593                 //  receiver function [from arguments]
    1594                 //  receiver this object [from arguments]
    1595 
    1596                 QtConnectionObject* conn = QtConnectionObject::createWithInternalJSC(exec, d->m_instance, signalIndex, thisObject, funcObject);
    1597                 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
    1598                 if (!ok) {
    1599                     delete conn;
    1600                     QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
    1601                             .arg(QLatin1String(sender->metaObject()->className()))
    1602                             .arg(QLatin1String(d->m_signature));
    1603                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
    1604                 }
    1605                 else {
    1606                     // Store connection
    1607                     connections.insert(sender, conn);
    1608                 }
    1609             } else {
    1610                 // Now to find our previous connection object. Hmm.
    1611                 QList<QtConnectionObject*> conns = connections.values(sender);
    1612                 bool ret = false;
    1613 
    1614                 JSContextRef context = ::toRef(exec);
    1615                 JSObjectRef receiver = ::toRef(thisObject);
    1616                 JSObjectRef receiverFunction = ::toRef(funcObject);
    1617 
    1618                 foreach(QtConnectionObject* conn, conns) {
    1619                     // Is this the right connection?
    1620                     if (conn->match(context, sender, signalIndex, receiver, receiverFunction)) {
    1621                         // Yep, disconnect it
    1622                         QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
    1623                         delete conn; // this will also remove it from the map
    1624                         ret = true;
    1625                         break;
    1626                     }
    1627                 }
    1628 
    1629                 if (!ret) {
    1630                     QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
    1631                             .arg(QLatin1String(sender->metaObject()->className()))
    1632                             .arg(QLatin1String(d->m_signature));
    1633                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
    1634                 }
    1635             }
    1636         } else {
    1637             QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
    1638                     .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
    1639                     .arg(QLatin1String(sender->metaObject()->className()))
    1640                     .arg(QLatin1String(d->m_signature));
    1641             return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
    1642         }
    1643     } else {
    1644         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
    1645     }
    1646 
    1647     return JSValue::encode(jsUndefined());
    1648 }
    1649 
    1650 CallType QtRuntimeConnectionMethod::getCallData(JSCell*, CallData& callData)
    1651 {
    1652     callData.native.function = call;
    1653     return CallTypeHost;
    1654 }
    1655 
    1656 bool QtRuntimeConnectionMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    1657 {
    1658     QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(cell);
    1659     if (propertyName == exec->propertyNames().length) {
    1660         slot.setCustom(thisObject, thisObject->lengthGetter);
    1661         return true;
    1662     }
    1663 
    1664     return QtRuntimeMethod::getOwnPropertySlot(thisObject, exec, propertyName, slot);
    1665 }
    1666 
    1667 bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
    1668 {
    1669     QtRuntimeConnectionMethod* thisObject = jsCast<QtRuntimeConnectionMethod*>(object);
    1670     if (propertyName == exec->propertyNames().length) {
    1671         PropertySlot slot;
    1672         slot.setCustom(thisObject, lengthGetter);
    1673         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
    1674         return true;
    1675     }
    1676 
    1677     return QtRuntimeMethod::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
    1678 }
    1679 
    1680 void QtRuntimeConnectionMethod::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    1681 {
    1682     if (mode == IncludeDontEnumProperties)
    1683         propertyNames.add(exec->propertyNames().length);
    1684 
    1685     QtRuntimeMethod::getOwnPropertyNames(object, exec, propertyNames, mode);
    1686 }
    1687 
    1688 JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, PropertyName)
    1689 {
    1690     // we have one formal argument, and one optional
    1691     return jsNumber(1);
    1692 }
    1693 
    1694 // ===============
     1523QMultiMap<QObject*, QtConnectionObject*> QtConnectionObject::connections;
    16951524
    16961525QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
     
    17121541    // We can safely use m_originalSender because connection object will never outlive the sender,
    17131542    // which is its QObject parent.
    1714     QtRuntimeConnectionMethod::connections.remove(m_originalSender, this);
     1543    connections.remove(m_originalSender, this);
    17151544
    17161545    if (m_receiver)
     
    18461675}
    18471676
    1848 QtConnectionObject* QtConnectionObject::createWithInternalJSC(ExecState* exec, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction)
    1849 {
    1850     return new QtConnectionObject(::toRef(exec), senderInstance, signalIndex, ::toRef(receiver), ::toRef(receiverFunction));
    1851 }
    1852 
    18531677// ===============
    18541678
  • trunk/Source/WebCore/bridge/qt/qt_runtime.h

    r125032 r125428  
    9696};
    9797
    98 // Based on RuntimeMethod
     98class QtRuntimeMethod {
     99public:
     100    enum MethodFlags {
     101        MethodIsSignal = 1,
     102        AllowPrivate = 2
     103    };
    99104
    100 // Extra data classes (to avoid the CELL_SIZE limit on JS objects)
    101 class QtRuntimeMethod;
    102 class QtRuntimeMethodData : public WeakHandleOwner {
    103     public:
    104         virtual ~QtRuntimeMethodData();
    105         RefPtr<QtInstance> m_instance;
    106         Weak<QtRuntimeMethod> m_finalizer;
     105    QtRuntimeMethod(JSContextRef, JSValueRef* exception, QObject*, const QByteArray& identifier, int signalIndex, int flags, QtInstance*);
     106    ~QtRuntimeMethod();
    107107
    108     private:
    109         void finalize(Handle<Unknown>, void*);
    110 };
     108    static JSValueRef call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
     109    static JSValueRef connect(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
     110    static JSValueRef disconnect(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
    111111
    112 class QtRuntimeConnectionMethod;
    113 class QtRuntimeMetaMethodData : public QtRuntimeMethodData {
    114     public:
    115         ~QtRuntimeMetaMethodData();
    116         QByteArray m_signature;
    117         bool m_allowPrivate;
    118         int m_index;
    119         WriteBarrier<QtRuntimeConnectionMethod> m_connect;
    120         WriteBarrier<QtRuntimeConnectionMethod> m_disconnect;
    121 };
     112    JSObjectRef jsObjectRef(JSContextRef, JSValueRef* exception);
    122113
    123 class QtRuntimeConnectionMethodData : public QtRuntimeMethodData {
    124     public:
    125         ~QtRuntimeConnectionMethodData();
    126         QByteArray m_signature;
    127         int m_index;
    128         bool m_isConnect;
    129 };
    130 
    131 // Common base class (doesn't really do anything interesting)
    132 class QtRuntimeMethod : public InternalFunction {
    133 public:
    134     typedef InternalFunction Base;
    135 
    136     ~QtRuntimeMethod();
    137     static void destroy(JSCell*);
    138 
    139     static const ClassInfo s_info;
    140 
    141     static FunctionPrototype* createPrototype(ExecState*, JSGlobalObject* globalObject)
    142     {
    143         return globalObject->functionPrototype();
    144     }
    145 
    146     static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
    147     {
    148         return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType,  StructureFlags), &s_info);
    149     }
    150 
    151 protected:
    152     void finishCreation(ExecState*, const UString&, PassRefPtr<QtInstance>);
    153     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InternalFunction::StructureFlags | OverridesVisitChildren;
    154 
    155     QtRuntimeMethodData *d_func() const {return d_ptr;}
    156     QtRuntimeMethod(QtRuntimeMethodData *dd, ExecState *, Structure*, const UString& name);
    157     QtRuntimeMethodData *d_ptr;
    158 };
    159 
    160 class QtRuntimeMetaMethod : public QtRuntimeMethod {
    161 public:
    162     typedef QtRuntimeMethod Base;
    163 
    164     static QtRuntimeMetaMethod* create(ExecState* exec, const UString& name, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature, bool allowPrivate)
    165     {
    166         Structure* domStructure = WebCore::deprecatedGetDOMStructure<QtRuntimeMetaMethod>(exec);
    167         QtRuntimeMetaMethod* method = new (allocateCell<QtRuntimeMetaMethod>(*exec->heap())) QtRuntimeMetaMethod(exec, domStructure, name);
    168         method->finishCreation(exec, name, instance, index, signature, allowPrivate);
    169         return method;
    170     }
    171 
    172     static bool getOwnPropertySlot(JSCell*, ExecState *, PropertyName, PropertySlot&);
    173     static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
    174     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    175 
    176     static void visitChildren(JSCell*, SlotVisitor&);
    177    
    178     static const ClassInfo s_info;
    179 
    180     static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
    181     {
    182         return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType,  StructureFlags), &s_info);
    183     }
    184 
    185 protected:
    186     QtRuntimeMetaMethodData* d_func() const {return reinterpret_cast<QtRuntimeMetaMethodData*>(d_ptr);}
     114    const QByteArray& name() { return m_identifier; }
    187115
    188116private:
    189     QtRuntimeMetaMethod(ExecState*, Structure*, const UString&);
    190     void finishCreation(ExecState*, const UString&, PassRefPtr<QtInstance>, int index, const QByteArray& signature, bool allowPrivate);
     117    static const JSStaticFunction connectFunction;
     118    static const JSStaticFunction disconnectFunction;
    191119
    192     static CallType getCallData(JSCell*, CallData&);
    193     static EncodedJSValue JSC_HOST_CALL call(ExecState* exec);
    194     static JSValue lengthGetter(ExecState*, JSValue, PropertyName);
    195     static JSValue connectGetter(ExecState*, JSValue, PropertyName);
    196     static JSValue disconnectGetter(ExecState*, JSValue, PropertyName);
    197 };
    198 
    199 class QtConnectionObject;
    200 class QtRuntimeConnectionMethod : public QtRuntimeMethod {
    201 public:
    202     typedef QtRuntimeMethod Base;
    203 
    204     static QtRuntimeConnectionMethod* create(ExecState* exec, const UString& name, bool isConnect, PassRefPtr<QtInstance> instance, int index, const QByteArray& signature)
    205     {
    206         Structure* domStructure = WebCore::deprecatedGetDOMStructure<QtRuntimeConnectionMethod>(exec);
    207         QtRuntimeConnectionMethod* method = new (allocateCell<QtRuntimeConnectionMethod>(*exec->heap())) QtRuntimeConnectionMethod(exec, domStructure, name);
    208         method->finishCreation(exec, name, isConnect, instance, index, signature);
    209         return method;
    210     }
    211 
    212     static bool getOwnPropertySlot(JSCell*, ExecState *, PropertyName, PropertySlot&);
    213     static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
    214     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    215  
    216     static const ClassInfo s_info;
    217 
    218     static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
    219     {
    220         return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType,  StructureFlags), &s_info);
    221     }
    222 
    223 protected:
    224     QtRuntimeConnectionMethodData* d_func() const {return reinterpret_cast<QtRuntimeConnectionMethodData*>(d_ptr);}
    225 
    226 private:
    227     QtRuntimeConnectionMethod(ExecState*, Structure*, const UString&);
    228     void finishCreation(ExecState*, const UString&, bool isConnect, PassRefPtr<QtInstance>, int index, const QByteArray& signature);
    229 
    230     static CallType getCallData(JSCell*, CallData&);
    231     static EncodedJSValue JSC_HOST_CALL call(ExecState* exec);
    232     static JSValue lengthGetter(ExecState*, JSValue, PropertyName);
    233     static QMultiMap<QObject *, QtConnectionObject *> connections;
    234     friend class QtConnectionObject;
     120    static JSValueRef connectOrDisconnect(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception, bool connect);
     121    QPointer<QObject> m_object;
     122    QByteArray m_identifier;
     123    int m_index;
     124    int m_flags;
     125    Weak<JSObject> m_jsObject;
     126    QtInstance* m_instance;
    235127};
    236128
     
    248140    bool match(JSContextRef, QObject* sender, int signalIndex, JSObjectRef thisObject, JSObjectRef funcObject);
    249141
    250     // Note: for callers using JSC internals, remove once we don't need anymore.
    251     static QtConnectionObject* createWithInternalJSC(ExecState*, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction);
    252 
    253142private:
    254143    JSGlobalContextRef m_context;
     
    261150    JSObjectRef m_receiver;
    262151    JSObjectRef m_receiverFunction;
     152
     153    friend class QtRuntimeMethod;
     154    static QMultiMap<QObject*, QtConnectionObject*> connections;
    263155};
    264156
  • trunk/Source/WebKit/qt/ChangeLog

    r125411 r125428  
     12012-08-13  Simon Hausmann  <simon.hausmann@nokia.com>
     2
     3        [Qt] Port meta method/signal/slot handling in run-time bridge to use JSC C API
     4        https://bugs.webkit.org/show_bug.cgi?id=93476
     5
     6        Reviewed by Kenneth Rohde Christiansen.
     7
     8        Changed semantics of some test expectations. Similarly to r125032 when generating
     9        error exceptions for connect/disconnect, we cannot generate explicit type error
     10        exceptions but only generic errors. Another change is that the meta-method wrapper
     11        doesn't support the call() through Function.prototype anymore. See WebCore changelog
     12        for details.
     13
     14        * tests/qobjectbridge/tst_qobjectbridge.cpp:
     15        (tst_QObjectBridge::connectAndDisconnect):
     16        (tst_QObjectBridge::objectDeleted):
     17        (tst_QObjectBridge::introspectQtMethods):
     18
    1192012-08-13  Kwang Yul Seo  <skyul@company100.net>
    220
  • trunk/Source/WebKit/qt/tests/qobjectbridge/tst_qobjectbridge.cpp

    r125275 r125428  
    15001500
    15011501    // connect(obj, string)
    1502     QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
    1503     QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
    1504     QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
    1505     QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
     1502    {
     1503        QString type;
     1504        QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')", type), sUndefined);
     1505        QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')", type), sUndefined);
     1506        QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')", type), sUndefined);
     1507        QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')", type), sUndefined);
     1508    }
    15061509
    15071510    // check that emitting signals from script works
     
    15561559    QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
    15571560
     1561    QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject, 'myOverloadedSlot(int)')"), sUndefined);
     1562    m_myObject->resetQtFunctionInvoked();
     1563    QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
     1564    QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
     1565    QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
     1566    QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
     1567    QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject, 'myOverloadedSlot(int)')"), sUndefined);
     1568
    15581569    // erroneous input
    15591570    {
     
    15881599        QString ret = evalJS("myObject.myInvokable.connect(123)", type);
    15891600        QCOMPARE(type, sError);
    1590         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
     1601        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
    15911602    }
    15921603    {
     
    15941605        QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
    15951606        QCOMPARE(type, sError);
    1596         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
     1607        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
    15971608    }
    15981609
     
    16011612        QString ret = evalJS("myObject.mySignal.connect(123)", type);
    16021613        QCOMPARE(type, sError);
    1603         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
     1614        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
     1615    }
     1616
     1617    {
     1618        QString type;
     1619        QString ret = evalJS("var randomObject = new Object; myObject.mySignal.connect(myObject, randomObject)", type);
     1620        QCOMPARE(type, sError);
     1621        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
     1622    }
     1623
     1624    {
     1625        QString type;
     1626        QString ret = evalJS("myObject.mySignal.connect(myObject, 'nonExistantSlot')", type);
     1627        QCOMPARE(type, sError);
     1628        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.connect: target is not a function"));
    16041629    }
    16051630
     
    16171642    }
    16181643
     1644    {
     1645        QString type;
     1646        QString ret = evalJS("myObject.mySignal.disconnect(myObject, 'nonExistantSlot')", type);
     1647        QCOMPARE(type, sError);
     1648        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: target is not a function"));
     1649    }
     1650
    16191651    /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
    16201652    {
     
    16301662        QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
    16311663        QCOMPARE(type, sError);
    1632         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
     1664        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
    16331665    }
    16341666
     
    16371669        QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
    16381670        QCOMPARE(type, sError);
    1639         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
     1671        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
    16401672    }
    16411673    {
     
    16431675        QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
    16441676        QCOMPARE(type, sError);
    1645         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
     1677        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
    16461678    }
    16471679
     
    16501682        QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
    16511683        QCOMPARE(type, sError);
    1652         QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
     1684        QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: target is not a function"));
    16531685    }
    16541686
     
    18481880    QCOMPARE(qobj->intProperty(), 123);
    18491881    qobj->resetQtFunctionInvoked();
    1850     evalJS("bar.myInvokable.call(bar);");
     1882    evalJS("bar.myInvokable(bar);");
    18511883    QCOMPARE(qobj->qtFunctionInvoked(), 0);
    18521884
     
    21462178        QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
    21472179        QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
    2148         QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse);
     2180        QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sTrue);
    21492181    }
    21502182
Note: See TracChangeset for help on using the changeset viewer.