From a267b590d17d1e7088acf44a8ba7e307f898ccb1 Mon Sep 17 00:00:00 2001
From: Kent Hansen <khansen@trolltech.com>
Date: Mon, 13 Jul 2009 11:18:22 +0200
Subject: add GC marking guards

Caller is responsible for calling marked() before mark(),
otherwise you might get infinite recursion.
---
 src/script/api/qscriptengine.cpp     | 20 +++++++++++++-------
 src/script/bridge/qscriptobject.cpp  |  6 ++++--
 src/script/bridge/qscriptqobject.cpp | 21 +++++++++++++++------
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp
index bf76cd4..4800286 100644
--- a/src/script/api/qscriptengine.cpp
+++ b/src/script/api/qscriptengine.cpp
@@ -563,17 +563,19 @@ void GlobalObject::mark()
     if (engine->uncaughtException)
         engine->uncaughtException.mark();
 
-    if (engine->qobjectPrototype)
+    if (engine->qobjectPrototype && !engine->qobjectPrototype->marked())
         engine->qobjectPrototype->mark();
-    if (engine->qmetaobjectPrototype)
+    if (engine->qmetaobjectPrototype && !engine->qmetaobjectPrototype->marked())
         engine->qmetaobjectPrototype->mark();
-    if (engine->variantPrototype)
+    if (engine->variantPrototype && !engine->variantPrototype->marked())
         engine->variantPrototype->mark();
 
     {
         QHash<JSC::JSCell*,QBasicAtomicInt>::const_iterator it;
         for (it = engine->keepAliveValues.constBegin(); it != engine->keepAliveValues.constEnd(); ++it) {
-            it.key()->mark();
+            JSC::JSCell *cell = it.key();
+            if (!cell->marked())
+                cell->mark();
         }
     }
 
@@ -590,7 +592,7 @@ void GlobalObject::mark()
     {
         QHash<int, QScriptTypeInfo*>::const_iterator it;
         for (it = engine->m_typeInfos.constBegin(); it != engine->m_typeInfos.constEnd(); ++it) {
-            if ((*it)->prototype)
+            if ((*it)->prototype && !(*it)->prototype.marked())
                 (*it)->prototype.mark();
         }
     }
@@ -1413,8 +1415,10 @@ QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
     if (!object.isObject())
         return newVariant(value);
     JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(object)->jscValue);
-    if (!jscObject->isObject(&QScriptObject::info))
+    if (!jscObject->isObject(&QScriptObject::info)) {
+        qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
         return QScriptValue();
+    }
     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
     if (!object.isVariant()) {
         delete jscScriptObject->delegate();
@@ -1489,8 +1493,10 @@ QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
     if (!scriptObject.isObject())
         return newQObject(qtObject, ownership, options);
     JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
-    if (!jscObject->isObject(&QScriptObject::info))
+    if (!jscObject->isObject(&QScriptObject::info)) {
+        qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
         return QScriptValue();
+    }
     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
     if (!scriptObject.isQObject()) {
         delete jscScriptObject->delegate();
diff --git a/src/script/bridge/qscriptobject.cpp b/src/script/bridge/qscriptobject.cpp
index b657af7..5cf415a 100644
--- a/src/script/bridge/qscriptobject.cpp
+++ b/src/script/bridge/qscriptobject.cpp
@@ -113,7 +113,8 @@ void QScriptObject::getPropertyNames(JSC::ExecState* exec, JSC::PropertyNameArra
 
 void QScriptObject::mark()
 {
-    if (d && d->data)
+    Q_ASSERT(!marked());
+    if (d && d->data && !d->data.marked())
         d->data.mark();
     if (!d || !d->delegate) {
         JSC::JSObject::mark();
@@ -203,7 +204,8 @@ void QScriptObjectDelegate::getPropertyNames(QScriptObject* object, JSC::ExecSta
 
 void QScriptObjectDelegate::mark(QScriptObject* object)
 {
-    object->JSC::JSObject::mark();
+    if (!object->marked())
+        object->JSC::JSObject::mark();
 }
 
 JSC::CallType QScriptObjectDelegate::getCallData(QScriptObject* object, JSC::CallData& data)
diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp
index a17daea..ff58102 100644
--- a/src/script/bridge/qscriptqobject.cpp
+++ b/src/script/bridge/qscriptqobject.cpp
@@ -82,9 +82,9 @@ struct QObjectConnection
             }
 #endif
         }
-        if (receiver)
+        if (receiver && !receiver.marked())
             receiver.mark();
-        if (slot)
+        if (slot && !slot.marked())
             slot.mark();
     }
 };
@@ -234,7 +234,13 @@ JSC::CallType QtFunction::getCallData(JSC::CallData &callData)
 
 void QtFunction::mark()
 {
-    data->object.mark();
+    Q_ASSERT(!marked());
+    if (data->object && !data->object.marked()) {
+        // FIXME: Causes infinite recursion because the object will mark this function,
+        // which will again mark the object, and so on. Need an "is marking" flag.
+//        data->object.mark();
+    }
+    JSC::InternalFunction::mark();
 }
 
 QScriptObject *QtFunction::wrapperObject() const
@@ -1498,10 +1504,13 @@ void QObjectDelegate::getPropertyNames(QScriptObject *object, JSC::ExecState *ex
 void QObjectDelegate::mark(QScriptObject *object)
 {
     QHash<QByteArray, JSC::JSValue>::const_iterator it;
-    for (it = data->cachedMembers.constBegin(); it != data->cachedMembers.constEnd(); ++it)
-        JSC::asObject(it.value())->mark();
+    for (it = data->cachedMembers.constBegin(); it != data->cachedMembers.constEnd(); ++it) {
+        JSC::JSValue val = it.value();
+        if (val && !val.marked())
+            val.mark();
+    }
 
-    object->JSC::JSObject::mark();
+    QScriptObjectDelegate::mark(object);
 }
 
 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*,
-- 
cgit v0.12