Skip to content
Permalink
Browse files
[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):

Canonical link: https://commits.webkit.org/111703@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@125428 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
tronical committed Aug 13, 2012
1 parent e127ccf commit 6c161ca192e9a430b1b25c3821bd092e69972099
Showing 8 changed files with 346 additions and 572 deletions.
@@ -1,3 +1,50 @@
2012-08-13 Simon Hausmann <simon.hausmann@nokia.com>

[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.

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):

2012-08-13 Leandro Gracia Gil <leandrogracia@chromium.org>

[Chromium] Fix nits in the find-in-page match rects API
@@ -20,6 +20,7 @@
#include "config.h"
#include "qt_class.h"

#include "APICast.h"
#include "Identifier.h"
#include "qt_instance.h"
#include "qt_runtime.h"
@@ -69,44 +70,48 @@ const char* QtClass::name() const
JSValue QtClass::fallbackObject(ExecState* exec, Instance* inst, PropertyName identifier)
{
QtInstance* qtinst = static_cast<QtInstance*>(inst);
JSContextRef context = toRef(exec);
JSValueRef* exception = 0;

UString ustring(identifier.publicName());
const QByteArray name = QString(reinterpret_cast<const QChar*>(ustring.characters()), ustring.length()).toLatin1();

// First see if we have a cache hit
JSObject* val = qtinst->m_methods.value(name).get();
if (val)
return val;
if (QtRuntimeMethod* method = qtinst->m_methods.value(name))
return toJS(method->jsObjectRef(context, exception));

// Nope, create an entry
const QByteArray normal = QMetaObject::normalizedSignature(name.constData());

// See if there is an exact match
int index = -1;
QMetaMethod metaMethod;
if (normal.contains('(') && (index = m_metaObject->indexOfMethod(normal)) != -1) {
QMetaMethod m = m_metaObject->method(index);
if (m.access() != QMetaMethod::Private) {
QtRuntimeMetaMethod* val = QtRuntimeMetaMethod::create(exec, ustring, static_cast<QtInstance*>(inst), index, normal, false);
qtinst->m_methods.insert(name, val);
return val;
}
metaMethod = m_metaObject->method(index);
if (metaMethod.access() == QMetaMethod::Private)
index = -1;
}

// Nope.. try a basename match
const int count = m_metaObject->methodCount();
for (index = count - 1; index >= 0; --index) {
const QMetaMethod m = m_metaObject->method(index);
if (m.access() == QMetaMethod::Private)
continue;

if (normal == m.name()) {
QtRuntimeMetaMethod* val = QtRuntimeMetaMethod::create(exec, ustring, static_cast<QtInstance*>(inst), index, normal, false);
qtinst->m_methods.insert(name, val);
return val;
if (index == -1) {
const int count = m_metaObject->methodCount();
for (index = count - 1; index >= 0; --index) {
metaMethod = m_metaObject->method(index);
if (metaMethod.access() == QMetaMethod::Private)
continue;

if (metaMethod.name() == normal)
break;
}
}

return jsUndefined();
if (index == -1)
return jsUndefined();

int flags = metaMethod.methodType() == QMetaMethod::Signal ? QtRuntimeMethod::MethodIsSignal : 0;
QtRuntimeMethod* method = new QtRuntimeMethod(context, exception, static_cast<QtInstance*>(inst)->getObject(), normal, index, flags, qtinst);
qtinst->m_methods.insert(name, method);
return toJS(method->jsObjectRef(context, exception));
}

// This functionality is handled by the fallback case above...
@@ -94,7 +94,7 @@ QtInstance::~QtInstance()

cachedInstances.remove(m_hashkey);

// clean up (unprotect from gc) the JSValues we've created
qDeleteAll(m_methods);
m_methods.clear();

qDeleteAll(m_fields);
@@ -147,16 +147,6 @@ void QtInstance::put(JSObject* object, ExecState* exec, PropertyName propertyNam
JSObject::put(object, exec, propertyName, value, slot);
}

void QtInstance::removeUnusedMethods()
{
for (QHash<QByteArray, QtWeakObjectReference>::Iterator it = m_methods.begin(), end = m_methods.end(); it != end; ) {
if (!it.value().get())
it = m_methods.erase(it);
else
++it;
}
}

QtInstance* QtInstance::getInstance(JSObject* object)
{
if (!object)
@@ -179,6 +169,7 @@ Class* QtInstance::getClass() const
RuntimeObject* QtInstance::newRuntimeObject(ExecState* exec)
{
JSLockHolder lock(exec);
qDeleteAll(m_methods);
m_methods.clear();
return QtRuntimeObject::create(exec, exec->lexicalGlobalObject(), this);
}
@@ -33,7 +33,7 @@ namespace Bindings {

class QtClass;
class QtField;
class QtRuntimeMetaMethod;
class QtRuntimeMethod;

class QtInstance : public Instance {
public:
@@ -71,44 +71,9 @@ class QtInstance : public Instance {
virtual bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
virtual void put(JSObject*, ExecState*, PropertyName, JSValue, PutPropertySlot&);

void removeUnusedMethods();

static QtInstance* getInstance(JSObject*);

private:

class QtWeakObjectReference {
public:
QtWeakObjectReference(JSObject* reference)
: m_reference(reference)
{
}

QtWeakObjectReference(const QtWeakObjectReference& source)
: m_reference(source.m_reference.get())
{
}

QtWeakObjectReference()
: m_reference()
{
}

QtWeakObjectReference& operator=(const QtWeakObjectReference& source)
{
m_reference = PassWeak<JSObject>(source.m_reference.get());
return *this;
}

JSObject* get() const
{
return m_reference.get();
}

private:
Weak<JSObject> m_reference;
};

static PassRefPtr<QtInstance> create(QObject *instance, PassRefPtr<RootObject> rootObject, ValueOwnership ownership)
{
return adoptRef(new QtInstance(instance, rootObject, ownership));
@@ -120,7 +85,7 @@ class QtInstance : public Instance {
mutable QtClass* m_class;
QPointer<QObject> m_object;
QObject* m_hashkey;
mutable QHash<QByteArray, QtWeakObjectReference> m_methods;
mutable QHash<QByteArray, QtRuntimeMethod*> m_methods;
mutable QHash<QString, QtField*> m_fields;
ValueOwnership m_ownership;
};

0 comments on commit 6c161ca

Please sign in to comment.