Changeset 88635 in webkit


Ignore:
Timestamp:
Jun 13, 2011 6:41:44 AM (13 years ago)
Author:
caio.oliveira@openbossa.org
Message:

2011-06-13 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>

Reviewed by Andreas Kling.

[Qt] JSC Bridge: convert QtConnectionObject to use JSC API
https://bugs.webkit.org/show_bug.cgi?id=62330

This patch is based on the draft patch by Noam Rosenthal in bug 60842.
Qt API autotests cover the bridge behavior and pass after this patch.

  • bridge/qt/qt_runtime.h: Change QtConnectionObject to use JSC API types. In particular, we got rid of Strong<JSObject> members. Renamed some members and arguments to follow existing naming in QObject::connect().
  • bridge/qt/qt_runtime.cpp: (JSC::Bindings::QtRuntimeConnectionMethod::call): Use a new helper function to create a connection, passing the ExecState* that will be used when the connection is activated (signal emitted). Use JSC API types when looking up the matching signal to disconnect.

(JSC::Bindings::QtConnectionObject::QtConnectionObject): Use JSC API to
protect the receiver and receiverFunction from being garbage
collected. Removed the ASSERT() since we don't hold ProtectedPtrs (in current
code were Strong<>) anymore.

(JSC::Bindings::QtConnectionObject::~QtConnectionObject): Explain why is safe
to use m_originalSender here. Unprotect values that we protected in constructor.

(JSC::Bindings::isJavaScriptFunction): Helper function to identify whether a
JSObjectRef is a JS function (in contrast to a native function exposed to JS).

(JSC::Bindings::QtConnectionObject::execute):
(JSC::Bindings::QtConnectionObject::match):
Both updated to use JSC API when appliable. Note that convertQVariantToValue
still returns JSC internal types, will be handled in a different patch.

(JSC::Bindings::QtConnectionObject::createWithInternalJSC):
Convenince for the existing caller until it is converted to JSC as well.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r88634 r88635  
     12011-06-13  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
     2
     3        Reviewed by Andreas Kling.
     4
     5        [Qt] JSC Bridge: convert QtConnectionObject to use JSC API
     6        https://bugs.webkit.org/show_bug.cgi?id=62330
     7
     8        This patch is based on the draft patch by Noam Rosenthal in bug 60842.
     9        Qt API autotests cover the bridge behavior and pass after this patch.
     10
     11        * bridge/qt/qt_runtime.h: Change QtConnectionObject to use JSC API types. In
     12        particular, we got rid of Strong<JSObject> members. Renamed some members and
     13        arguments to follow existing naming in QObject::connect().
     14
     15        * bridge/qt/qt_runtime.cpp:
     16        (JSC::Bindings::QtRuntimeConnectionMethod::call): Use a new helper function
     17        to create a connection, passing the ExecState* that will be used when the
     18        connection is activated (signal emitted). Use JSC API types when looking up
     19        the matching signal to disconnect.
     20
     21        (JSC::Bindings::QtConnectionObject::QtConnectionObject): Use JSC API to
     22        protect the receiver and receiverFunction from being garbage
     23        collected. Removed the ASSERT() since we don't hold ProtectedPtrs (in current
     24        code were Strong<>) anymore.
     25
     26        (JSC::Bindings::QtConnectionObject::~QtConnectionObject): Explain why is safe
     27        to use m_originalSender here. Unprotect values that we protected in constructor.
     28
     29        (JSC::Bindings::isJavaScriptFunction): Helper function to identify whether a
     30        JSObjectRef is a JS function (in contrast to a native function exposed to JS).
     31
     32        (JSC::Bindings::QtConnectionObject::execute):
     33        (JSC::Bindings::QtConnectionObject::match):
     34        Both updated to use JSC API when appliable. Note that convertQVariantToValue
     35        still returns JSC internal types, will be handled in a different patch.
     36
     37        (JSC::Bindings::QtConnectionObject::createWithInternalJSC):
     38        Convenince for the existing caller until it is converted to JSC as well.
     39
    1402011-06-13  Carlos Garcia Campos  <cgarcia@igalia.com>
    241
  • trunk/Source/WebCore/bridge/qt/qt_runtime.cpp

    r87346 r88635  
    2121#include "qt_runtime.h"
    2222
     23#include "APICast.h"
    2324#include "BooleanObject.h"
    2425#include "DateInstance.h"
     
    3839#include "JSLock.h"
    3940#include "JSObject.h"
     41#include "JSRetainPtr.h"
    4042#include "ObjectPrototype.h"
    4143#include "PropertyNameArray.h"
     
    16431645                //  receiver this object [from arguments]
    16441646
    1645                 QtConnectionObject* conn = new QtConnectionObject(exec->globalData(), d->m_instance, signalIndex, thisObject, funcObject);
     1647                ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
     1648                QtConnectionObject* conn = QtConnectionObject::createWithInternalJSC(globalExec, d->m_instance, signalIndex, thisObject, funcObject);
    16461649                bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
    16471650                if (!ok) {
     
    16611664                bool ret = false;
    16621665
     1666                JSContextRef context = ::toRef(exec);
     1667                JSObjectRef receiver = ::toRef(thisObject);
     1668                JSObjectRef receiverFunction = ::toRef(funcObject);
     1669
    16631670                foreach(QtConnectionObject* conn, conns) {
    16641671                    // Is this the right connection?
    1665                     if (conn->match(sender, signalIndex, thisObject, funcObject)) {
     1672                    if (conn->match(context, sender, signalIndex, receiver, receiverFunction)) {
    16661673                        // Yep, disconnect it
    16671674                        QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
     
    17371744// ===============
    17381745
    1739 QtConnectionObject::QtConnectionObject(JSGlobalData& globalData, PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
    1740     : m_instance(instance)
     1746QtConnectionObject::QtConnectionObject(JSContextRef context, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
     1747    : QObject(senderInstance->getObject())
     1748    , m_context(context)
     1749    , m_senderInstance(senderInstance)
     1750    , m_originalSender(m_senderInstance->getObject())
    17411751    , m_signalIndex(signalIndex)
    1742     , m_originalObject(m_instance->getObject())
    1743     , m_thisObject(globalData, thisObject)
    1744     , m_funcObject(globalData, funcObject)
    1745 {
    1746     setParent(m_originalObject);
    1747     ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
     1752    , m_receiver(receiver)
     1753    , m_receiverFunction(receiverFunction)
     1754{
     1755    JSValueProtect(m_context, m_receiver);
     1756    JSValueProtect(m_context, m_receiverFunction);
    17481757}
    17491758
    17501759QtConnectionObject::~QtConnectionObject()
    17511760{
    1752     // Remove us from the map of active connections
    1753     QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
     1761    // We can safely use m_originalSender because connection object will never outlive the sender,
     1762    // which is its QObject parent.
     1763    QtRuntimeConnectionMethod::connections.remove(m_originalSender, this);
     1764
     1765    JSValueUnprotect(m_context, m_receiver);
     1766    JSValueUnprotect(m_context, m_receiverFunction);
    17541767}
    17551768
     
    17921805}
    17931806
     1807// This is what moc would generate except by the fact that we pass all arguments to our execute() slot.
    17941808int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
    17951809{
     
    18061820}
    18071821
    1808 void QtConnectionObject::execute(void **argv)
    1809 {
    1810     QObject* obj = m_instance->getObject();
    1811     if (obj) {
    1812         const QMetaObject* meta = obj->metaObject();
    1813         const QMetaMethod method = meta->method(m_signalIndex);
    1814 
    1815         QList<QByteArray> parameterTypes = method.parameterTypes();
    1816 
    1817         int argc = parameterTypes.count();
    1818 
    1819         JSLock lock(SilenceAssertionsOnly);
    1820 
    1821         // ### Should the Interpreter/ExecState come from somewhere else?
    1822         RefPtr<RootObject> ro = m_instance->rootObject();
    1823         if (ro) {
    1824             JSGlobalObject* globalobj = ro->globalObject();
    1825             if (globalobj) {
    1826                 ExecState* exec = globalobj->globalExec();
    1827                 if (exec) {
    1828                     // Build the argument list (up to the formal argument length of the slot)
    1829                     MarkedArgumentBuffer l;
    1830                     // ### DropAllLocks?
    1831                     int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
    1832                     int argTotal = qMax(funcArgC, argc);
    1833                     for(int i=0; i < argTotal; i++) {
    1834                         if (i < argc) {
    1835                             int argType = QMetaType::type(parameterTypes.at(i));
    1836                             l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
    1837                         } else {
    1838                             l.append(jsUndefined());
    1839                         }
    1840                     }
    1841 
    1842                     const bool withQtSenderStack = m_funcObject->inherits(&JSFunction::s_info);
    1843                     if (withQtSenderStack)
    1844                         QtInstance::qtSenderStack()->push(QObject::sender());
    1845 
    1846                     CallData callData;
    1847                     CallType callType = m_funcObject->getCallData(callData);
    1848                     call(exec, m_funcObject.get(), callType, callData, m_thisObject.get(), l);
    1849 
    1850                     if (withQtSenderStack)
    1851                         QtInstance::qtSenderStack()->pop();
    1852                 }
    1853             }
    1854         }
    1855     } else {
    1856         // A strange place to be - a deleted object emitted a signal here.
     1822static bool isJavaScriptFunction(JSObjectRef object)
     1823{
     1824    CallData callData;
     1825    return toJS(object)->getCallData(callData) == CallTypeJS;
     1826}
     1827
     1828void QtConnectionObject::execute(void** argv)
     1829{
     1830    QObject* sender = m_senderInstance->getObject();
     1831    if (!sender) {
    18571832        qWarning() << "sender deleted, cannot deliver signal";
    1858     }
    1859 }
    1860 
    1861 bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
    1862 {
    1863     if (m_originalObject == sender && m_signalIndex == signalIndex
    1864         && thisObject == (JSObject*)m_thisObject.get() && funcObject == (JSObject*)m_funcObject.get())
    1865         return true;
    1866     return false;
     1833        return;
     1834    }
     1835
     1836    ASSERT(sender == m_originalSender);
     1837
     1838    const QMetaObject* meta = sender->metaObject();
     1839    const QMetaMethod method = meta->method(m_signalIndex);
     1840
     1841    QList<QByteArray> parameterTypes = method.parameterTypes();
     1842
     1843    JSValueRef* ignoredException = 0;
     1844    JSRetainPtr<JSStringRef> lengthProperty(JSStringCreateWithUTF8CString("length"));
     1845    int receiverLength = int(JSValueToNumber(m_context, JSObjectGetProperty(m_context, m_receiverFunction, lengthProperty.get(), ignoredException), ignoredException));
     1846    int argc = qMax(parameterTypes.count(), receiverLength);
     1847    WTF::Vector<JSValueRef> args(argc);
     1848
     1849    // TODO: remove once conversion functions use JSC API.
     1850    ExecState* exec = ::toJS(m_context);
     1851    RefPtr<RootObject> rootObject = m_senderInstance->rootObject();
     1852
     1853    for (int i = 0; i < argc; i++) {
     1854        int argType = QMetaType::type(parameterTypes.at(i));
     1855        args[i] = ::toRef(exec, convertQVariantToValue(exec, rootObject, QVariant(argType, argv[i+1])));
     1856    }
     1857
     1858    const bool updateQtSender = isJavaScriptFunction(m_receiverFunction);
     1859    if (updateQtSender)
     1860        QtInstance::qtSenderStack()->push(QObject::sender());
     1861
     1862    JSObjectCallAsFunction(m_context, m_receiverFunction, m_receiver, argc, args.data(), 0);
     1863
     1864    if (updateQtSender)
     1865        QtInstance::qtSenderStack()->pop();
     1866}
     1867
     1868bool QtConnectionObject::match(JSContextRef context, QObject* sender, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction)
     1869{
     1870    if (sender != m_originalSender || signalIndex != m_signalIndex)
     1871        return false;
     1872    JSValueRef* ignoredException = 0;
     1873    const bool receiverMatch = (!receiver && !m_receiver) || JSValueIsEqual(context, receiver, m_receiver, ignoredException);
     1874    return receiverMatch && JSValueIsEqual(context, receiverFunction, m_receiverFunction, ignoredException);
     1875}
     1876
     1877QtConnectionObject* QtConnectionObject::createWithInternalJSC(ExecState* exec, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction)
     1878{
     1879    return new QtConnectionObject(::toRef(exec), senderInstance, signalIndex, ::toRef(receiver), ::toRef(receiverFunction));
    18671880}
    18681881
  • trunk/Source/WebCore/bridge/qt/qt_runtime.h

    r88361 r88635  
    2222
    2323#include "BridgeJSC.h"
    24 #include "Completion.h"
    25 #include "Strong.h"
     24#include "JavaScript.h"
    2625#include "Weak.h"
    2726#include "runtime_method.h"
     
    193192};
    194193
    195 class QtConnectionObject: public QObject
    196 {
    197 public:
    198     QtConnectionObject(JSGlobalData&, PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject);
     194// A QtConnectionObject represents a connection created inside JS. It will connect its own execute() slot
     195// with the appropriate signal of 'sender'. When execute() is called, it will call JS 'receiverFunction'.
     196class QtConnectionObject : public QObject
     197{
     198public:
     199    QtConnectionObject(JSContextRef, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObjectRef receiver, JSObjectRef receiverFunction);
    199200    ~QtConnectionObject();
    200201
     202    // Explicitly define these because want a custom qt_metacall(), so we can't use Q_OBJECT macro.
    201203    static const QMetaObject staticMetaObject;
    202204    virtual const QMetaObject *metaObject() const;
     
    204206    virtual int qt_metacall(QMetaObject::Call, int, void **argv);
    205207
    206     bool match(QObject *sender, int signalIndex, JSObject* thisObject, JSObject *funcObject);
    207 
    208     // actual slot:
    209208    void execute(void **argv);
    210209
    211 private:
    212     RefPtr<QtInstance> m_instance;
     210    bool match(JSContextRef, QObject* sender, int signalIndex, JSObjectRef thisObject, JSObjectRef funcObject);
     211
     212    // Note: for callers using JSC internals, remove once we don't need anymore.
     213    static QtConnectionObject* createWithInternalJSC(ExecState*, PassRefPtr<QtInstance> senderInstance, int signalIndex, JSObject* receiver, JSObject* receiverFunction);
     214
     215private:
     216    JSContextRef m_context;
     217    RefPtr<QtInstance> m_senderInstance;
     218
     219    // We use this as key in active connections multimap.
     220    QObject* m_originalSender;
     221
    213222    int m_signalIndex;
    214     QObject* m_originalObject; // only used as a key, not dereferenced
    215     Strong<JSObject> m_thisObject;
    216     Strong<JSObject> m_funcObject;
     223    JSObjectRef m_receiver;
     224    JSObjectRef m_receiverFunction;
    217225};
    218226
Note: See TracChangeset for help on using the changeset viewer.