Fix leak of v8 context used for implicit strong references.
authorSimon Hausmann <simon.hausmann@nokia.com>
Mon, 12 Dec 2011 12:41:25 +0000 (13:41 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 14 Dec 2011 08:55:28 +0000 (09:55 +0100)
QV8GCCallback::Referencer keeps strong implicit references for QObjects
owned by C++ (or objects with a CPP owned root parent). The implicit v8
object to express the implicit reference belongs to a dedicated v8 context,
which needs to be disposed properly.

Change-Id: Ic0555cb8d94384a185ebcee9825988d84e74f26b
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8gccallback_p.h

index 632a8ea..5207931 100644 (file)
@@ -1451,14 +1451,6 @@ void QV8GCCallback::registerGcPrologueCallback()
     }
 }
 
-void QV8GCCallback::ThreadData::releaseStrongReferencer()
-{
-    // NOTE: must be called with a valid current isolate
-    if (!referencer.strongReferencer.IsEmpty()) {
-        qPersistentDispose(referencer.strongReferencer);
-    }
-}
-
 void QV8GCCallback::releaseWorkerThreadGcPrologueCallbackData()
 {
     // Note that only worker-thread implementations with their
@@ -1467,7 +1459,7 @@ void QV8GCCallback::releaseWorkerThreadGcPrologueCallbackData()
     Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8GCCallback::releaseWorkerThreadGcPrologueCallbackData()", "called after v8::Isolate has exited");
     if (threadData.hasLocalData()) {
         QV8GCCallback::ThreadData *td = threadData.localData();
-        td->releaseStrongReferencer();
+        td->referencer.dispose();
     }
 }
 
@@ -1483,18 +1475,14 @@ QV8GCCallback::Node::~Node()
 
 QV8GCCallback::Referencer::~Referencer()
 {
-    if (!strongReferencer.IsEmpty()) {
-        Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8GCCallback::Referencer::~Referencer()", "called after v8::Isolate has exited");
-        // automatically release the strongReferencer if it hasn't
-        // been explicitly released already.
-        qPersistentDispose(strongReferencer);
-    }
+    dispose();
 }
 
 QV8GCCallback::Referencer::Referencer()
 {
     v8::HandleScope handleScope;
-    v8::Handle<v8::Context> context = v8::Context::New();
+    context = v8::Context::New();
+    qPersistentRegister(context);
     v8::Context::Scope contextScope(context);
     strongReferencer = qPersistentNew(v8::Object::New());
 }
@@ -1511,6 +1499,18 @@ void QV8GCCallback::Referencer::addRelationship(QObject *object, QObject *other)
     }
 }
 
+void QV8GCCallback::Referencer::dispose()
+{
+    if (!strongReferencer.IsEmpty()) {
+        Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8GCCallback::Referencer::~Referencer()", "called after v8::Isolate has exited");
+        // automatically release the strongReferencer if it hasn't
+        // been explicitly released already.
+        qPersistentDispose(strongReferencer);
+    }
+    if (!context.IsEmpty())
+        qPersistentDispose(context);
+}
+
 void QV8GCCallback::Referencer::addRelationship(QObject *object, v8::Persistent<v8::Value> handle)
 {
     if (handle.IsEmpty())
index f18b20b..297ac8a 100644 (file)
@@ -74,10 +74,12 @@ public:
         ~Referencer();
         void addRelationship(QObject *object, v8::Persistent<v8::Value> handle);
         void addRelationship(QObject *object, QObject *other);
+        void dispose();
     private:
         Referencer();
         static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *qobjectOwner, bool *shouldBeStrong);
         v8::Persistent<v8::Object> strongReferencer;
+        v8::Persistent<v8::Context> context;
         friend class QV8GCCallback::ThreadData;
     };
 
@@ -101,7 +103,6 @@ private:
         Referencer referencer;
         bool gcPrologueCallbackRegistered;
         QIntrusiveList<Node, &Node::node> gcCallbackNodes;
-        void releaseStrongReferencer();
     };
 
     static void initializeThreadData();