Michael Goddard <michael.goddard@trolltech.com>
authorhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 21 Apr 2008 14:29:13 +0000 (14:29 +0000)
committerhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 21 Apr 2008 14:29:13 +0000 (14:29 +0000)
Better handle Qt binding object lifetime in JS.
Add explicit marking of JS objects created for Qt
bindings, and remove the gcProtect calls.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@32315 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/bridge/qt/qt_class.cpp
WebCore/bridge/qt/qt_instance.cpp
WebCore/bridge/qt/qt_instance.h

index bf83938..2d40017 100644 (file)
@@ -2,6 +2,24 @@
 
         Reviewed by Simon.
 
+        Better handle Qt binding object lifetime in JS.
+        Add explicit marking of JS objects created for Qt
+        bindings, and remove the gcProtect calls.
+
+        * bridge/qt/qt_class.cpp:
+        (KJS::Bindings::QtClass::fallbackObject):
+        * bridge/qt/qt_instance.cpp:
+        (KJS::Bindings::QtRuntimeObjectImp::mark):
+        (KJS::Bindings::QtInstance::~QtInstance):
+        (KJS::Bindings::QtInstance::mark):
+        (KJS::Bindings::QtInstance::invokeDefaultMethod):
+        (KJS::Bindings::QtField::valueFromInstance):
+        * bridge/qt/qt_instance.h:
+
+2008-04-21  Michael Goddard  <michael.goddard@trolltech.com>
+
+        Reviewed by Simon.
+
         Add better support for RuntimeArray type conversions.
         It seems that RuntimeArray claims to inherit ArrayInstance
         (in the JS sense), but the C++ class doesn't, so properly
index 59730b8..adbac22 100644 (file)
@@ -66,10 +66,6 @@ const char* QtClass::name() const
 // and not get wrapped in RuntimeMethod).  Also, use this for methods,
 // so we can cache the JSValue* and return the same JSValue for the same
 // identifier...
-//
-// Unfortunately... we need to gcProtect our JSValues, since we don't have
-// access to an actual JS class that can mark() our JSValues.
-//
 JSValue* QtClass::fallbackObject(ExecState *exec, Instance *inst, const Identifier &identifier)
 {
     QtInstance* qtinst = static_cast<QtInstance*>(inst);
@@ -90,7 +86,6 @@ JSValue* QtClass::fallbackObject(ExecState *exec, Instance *inst, const Identifi
         QMetaMethod m = m_metaObject->method(index);
         if (m.access() != QMetaMethod::Private) {
             JSValue *val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
-            gcProtect(val);
             qtinst->m_methods.insert(name, val);
             return val;
         }
@@ -108,7 +103,6 @@ JSValue* QtClass::fallbackObject(ExecState *exec, Instance *inst, const Identifi
 
         if (normal == signature) {
             JSValue* val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
-            gcProtect(val);
             qtinst->m_methods.insert(name, val);
             return val;
         }
index 6c5eb22..d72d0e3 100644 (file)
@@ -51,6 +51,13 @@ class QtRuntimeObjectImp : public RuntimeObjectImp {
         ~QtRuntimeObjectImp();
         virtual void invalidate();
 
+        virtual void mark() {
+            QtInstance* instance = static_cast<QtInstance*>(getInternalInstance());
+            if (instance)
+                instance->mark();
+            RuntimeObjectImp::mark();
+        }
+
         // Additions
         virtual bool implementsConstruct() const {return implementsCall();}
         virtual JSObject* construct(ExecState* exec, const List& args);
@@ -112,18 +119,12 @@ QtInstance::~QtInstance()
     cachedInstances.remove(m_hashkey);
 
     // clean up (unprotect from gc) the JSValues we've created
-    foreach(JSValue* val, m_methods.values()) {
-        gcUnprotect(val);
-    }
     m_methods.clear();
 
     foreach(QtField* f, m_fields.values()) {
         delete f;
     }
     m_fields.clear();
-
-    if (m_defaultMethod)
-        gcUnprotect(m_defaultMethod);
 }
 
 PassRefPtr<QtInstance> QtInstance::getQtInstance(QObject* o, PassRefPtr<RootObject> rootObject)
@@ -159,6 +160,20 @@ Class* QtInstance::getClass() const
     return m_class;
 }
 
+void QtInstance::mark()
+{
+    if (m_defaultMethod)
+        m_defaultMethod->mark();
+    foreach(JSValue* val, m_methods.values()) {
+        if (val && !val->marked())
+            val->mark();
+    }
+    foreach(JSValue* val, m_children.values()) {
+        if (val && !val->marked())
+            val->mark();
+    }
+}
+
 void QtInstance::begin()
 {
     // Do nothing.
@@ -244,10 +259,8 @@ JSValue* QtInstance::invokeDefaultMethod(ExecState* exec, const List& args)
 
     // implementsCall will update our default method cache, if possible
     if (implementsCall()) {
-        if (!m_defaultMethod) {
+        if (!m_defaultMethod)
             m_defaultMethod = new QtRuntimeMetaMethod(exec, Identifier("[[Call]]"),this, m_defaultMethodIndex, QByteArray("qscript_call"), true);
-            gcProtect(m_defaultMethod);
-        }
 
         return m_defaultMethod->callAsFunction(exec, 0, args); // Luckily QtRuntimeMetaMethod ignores the obj parameter
     } else
@@ -357,7 +370,13 @@ JSValue* QtField::valueFromInstance(ExecState* exec, const Instance* inst) const
         else if (m_type == DynamicProperty)
             val = obj->property(m_dynamicProperty);
 
-        return convertQVariantToValue(exec, inst->rootObject(), val);
+        JSValue* ret = convertQVariantToValue(exec, inst->rootObject(), val);
+
+        // Need to save children so we can mark them
+        if (m_type == ChildObject)
+            instance->m_children.insert(ret);
+
+        return ret;
     } else {
         QString msg = QString("cannot access member `%1' of deleted QObject").arg(name());
         return throwError(exec, GeneralError, msg.toLatin1().constData());
index 4dc035b..75c1edf 100644 (file)
@@ -24,6 +24,7 @@
 #include "runtime_root.h"
 #include <qpointer.h>
 #include <qhash.h>
+#include <qset.h>
 
 namespace KJS {
 
@@ -53,6 +54,8 @@ public:
 
     virtual bool implementsCall() const;
 
+    virtual void mark(); // This isn't inherited
+
     virtual JSValue* invokeMethod (ExecState *exec, const MethodList &method, const List &args);
     virtual JSValue* invokeDefaultMethod (ExecState *exec, const List &args);
 
@@ -71,12 +74,14 @@ public:
 
 private:
     friend class QtClass;
+    friend class QtField;
     QtInstance(QObject*, PassRefPtr<RootObject>); // Factory produced only..
     mutable QtClass* m_class;
     QPointer<QObject> m_object;
     QObject* m_hashkey;
     mutable QHash<QByteArray,JSValue*> m_methods;
     mutable QHash<QString,QtField*> m_fields;
+    mutable QSet<JSValue*> m_children;
     mutable QtRuntimeMetaMethod* m_defaultMethod;
     mutable int m_defaultMethodIndex;
 };