Implement global handle tracking
authorAaron Kennedy <aaron.kennedy@nokia.com>
Wed, 8 Jun 2011 04:32:39 +0000 (14:32 +1000)
committerAaron Kennedy <aaron.kennedy@nokia.com>
Wed, 8 Jun 2011 04:32:39 +0000 (14:32 +1000)
This makes it easier to track down handles that have been double
Dispose()'d.  See qv8engine_p.h for details.

19 files changed:
src/declarative/qml/qdeclarativecontext.cpp
src/declarative/qml/qdeclarativeexpression.cpp
src/declarative/qml/qdeclarativepropertycache.cpp
src/declarative/qml/qdeclarativesqldatabase.cpp
src/declarative/qml/qdeclarativetypeloader.cpp
src/declarative/qml/qdeclarativevme.cpp
src/declarative/qml/qdeclarativevmemetaobject.cpp
src/declarative/qml/qdeclarativeworkerscript.cpp
src/declarative/qml/qdeclarativexmlhttprequest.cpp
src/declarative/qml/v8/qv8contextwrapper.cpp
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8engine_p.h
src/declarative/qml/v8/qv8include.cpp
src/declarative/qml/v8/qv8listwrapper.cpp
src/declarative/qml/v8/qv8qobjectwrapper.cpp
src/declarative/qml/v8/qv8typewrapper.cpp
src/declarative/qml/v8/qv8valuetypewrapper.cpp
src/declarative/qml/v8/qv8variantwrapper.cpp
src/declarative/util/qdeclarativelistmodel.cpp

index 5a24199..2b96d8f 100644 (file)
@@ -610,8 +610,9 @@ void QDeclarativeContextData::destroy()
     if (optimizedBindings)
         optimizedBindings->release();
 
-    for (int ii = 0; ii < importedScripts.count(); ++ii)
-        importedScripts[ii].Dispose();
+    for (int ii = 0; ii < importedScripts.count(); ++ii) {
+        qPersistentDispose(importedScripts[ii]);
+    }
 
     delete [] idValues;
 
index 557bb04..0438d23 100644 (file)
@@ -78,10 +78,8 @@ QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
 
 QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
 {
-    v8function.Dispose();
-    v8qmlscope.Dispose();
-    v8function = v8::Persistent<v8::Function>();
-    v8qmlscope = v8::Persistent<v8::Function>();
+    qPersistentDispose(v8function);
+    qPersistentDispose(v8qmlscope);
 
     if (guardList) { delete [] guardList; guardList = 0; }
     if (dataRef) dataRef->release();
@@ -116,7 +114,7 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Hand
     QDeclarativeAbstractExpression::setContext(ctxt);
     scopeObject = me;
 
-    v8function = v8::Persistent<v8::Function>::New(func);
+    v8function = qPersistentNew<v8::Function>(func);
     expressionFunctionMode = ExplicitContext;
     expressionFunctionValid = true;
 }
@@ -169,8 +167,8 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje
     v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
     v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
     v8::Local<v8::Value> result = script->Run(scopeobject);
-    if (qmlscope) *qmlscope = v8::Persistent<v8::Object>::New(scopeobject);
-    return v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(result));
+    if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+    return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
 }
 
 /*!
@@ -353,10 +351,8 @@ void QDeclarativeExpression::setExpression(const QString &expression)
     d->resetNotifyOnChange();
     d->expression = expression;
     d->expressionFunctionValid = false;
-    d->v8function.Dispose();
-    d->v8qmlscope.Dispose();
-    d->v8function = v8::Persistent<v8::Function>();
-    d->v8qmlscope = v8::Persistent<v8::Function>();
+    qPersistentDispose(d->v8function);
+    qPersistentDispose(d->v8qmlscope);
 }
 
 void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
index b2aad7b..783a66e 100644 (file)
@@ -168,8 +168,7 @@ void QDeclarativePropertyCache::clear()
     indexCache.clear();
     methodIndexCache.clear();
     stringCache.clear();
-    constructor.Dispose(); 
-    constructor.Clear();
+    qPersistentDispose(constructor);
 }
 
 QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject, 
@@ -251,8 +250,7 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
 {
     Q_UNUSED(revision);
 
-    constructor.Dispose(); // Now invalid
-    constructor.Clear();
+    qPersistentDispose(constructor); // Now invalid
 
     allowedRevisionCache.append(0);
 
index 5ceef36..df072ed 100644 (file)
@@ -194,8 +194,8 @@ static void qmlsqldatabase_rows_setForwardOnly(v8::Local<v8::String> property,
 
 QDeclarativeSqlDatabaseData::~QDeclarativeSqlDatabaseData()
 {
-    constructor.Dispose(); constructor = v8::Persistent<v8::Function>();
-    queryConstructor.Dispose(); queryConstructor = v8::Persistent<v8::Function>();
+    qPersistentDispose(constructor);
+    qPersistentDispose(queryConstructor);
 }
 
 static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
@@ -526,7 +526,7 @@ QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine)
     ft->PrototypeTemplate()->SetAccessor(v8::String::New("version"), qmlsqldatabase_version);
     ft->PrototypeTemplate()->Set(v8::String::New("changeVersion"), 
                                  V8FUNCTION(qmlsqldatabase_changeVersion, engine));
-    constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    constructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
 
     {
@@ -534,7 +534,7 @@ QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine)
     ft->InstanceTemplate()->SetHasExternalResource(true);
     ft->PrototypeTemplate()->Set(v8::String::New("executeSql"), 
                                  V8FUNCTION(qmlsqldatabase_executeSql, engine));
-    queryConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    queryConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
     {
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
@@ -544,7 +544,7 @@ QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine)
     ft->InstanceTemplate()->SetAccessor(v8::String::New("forwardOnly"), qmlsqldatabase_rows_forwardOnly, 
                                         qmlsqldatabase_rows_setForwardOnly);
     ft->InstanceTemplate()->SetIndexedPropertyHandler(qmlsqldatabase_rows_index);
-    rowsConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    rowsConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
 }
 
index 68fea5b..b4e6ef4 100644 (file)
@@ -1101,8 +1101,8 @@ void QDeclarativeScriptData::clear()
         scripts.at(ii)->release();
     scripts.clear();
 
-    m_program.Dispose();
-    m_value.Dispose();
+    qPersistentDispose(m_program);
+    qPersistentDispose(m_value);
 }
 
 QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
@@ -1237,7 +1237,7 @@ void QDeclarativeScriptBlob::done()
     v8::HandleScope handle_scope;
     v8::Context::Scope scope(v8engine->context());
     v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1);
-    m_scriptData->m_program = v8::Persistent<v8::Script>::New(program);
+    m_scriptData->m_program = qPersistentNew<v8::Script>(program);
 }
 
 QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
index ffe1e7a..c99551f 100644 (file)
@@ -964,7 +964,7 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData
 v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
 {
     if (script->m_loaded)
-        return v8::Persistent<v8::Object>::New(script->m_value);
+        return qPersistentNew<v8::Object>(script->m_value);
 
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine);
     QV8Engine *v8engine = &ep->v8engine;
@@ -1015,9 +1015,9 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC
         }
     } 
 
-    rv = v8::Persistent<v8::Object>::New(qmlglobal);
+    rv = qPersistentNew<v8::Object>(qmlglobal);
     if (shared) {
-        script->m_value = v8::Persistent<v8::Object>::New(qmlglobal);
+        script->m_value = qPersistentNew<v8::Object>(qmlglobal);
         script->m_loaded = true;
     }
 
index 97c7754..218b1c1 100644 (file)
@@ -419,8 +419,9 @@ QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
     delete parent;
     delete [] data;
 
-    for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii)
-        v8methods[ii].Dispose();
+    for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
+        qPersistentDispose(v8methods[ii]);
+    }
 }
 
 int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
@@ -845,7 +846,7 @@ void QDeclarativeVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Funct
 
     int methodIndex = index - methodOffset - plainSignals;
     if (!v8methods[methodIndex].IsEmpty()) 
-        v8methods[methodIndex].Dispose();
+        qPersistentDispose(v8methods[methodIndex]);
     v8methods[methodIndex] = value;
 }
 
index fd2b924..b519573 100644 (file)
@@ -196,8 +196,8 @@ QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWo
 
 QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() 
 { 
-    createsend.Dispose(); createsend.Clear();
-    onmessage.Dispose(); onmessage.Clear();
+    qPersistentDispose(createsend);
+    qPersistentDispose(onmessage);
     delete accessManager; 
 }
 
@@ -229,7 +229,7 @@ void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
 
     {
     v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
-    onmessage = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
+    onmessage = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
     }
     {
     v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
@@ -240,7 +240,7 @@ void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
     };
     v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
     
-    createsend = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(createsendvalue));
+    createsend = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(createsendvalue));
     }
 }
 
@@ -301,7 +301,7 @@ v8::Handle<v8::Object> QDeclarativeWorkerScriptEnginePrivate::getWorker(WorkerSc
     if (!script->initialized) {
         script->initialized = true;
 
-        script->object = v8::Persistent<v8::Object>::New(workerEngine->contextWrapper()->urlScope(script->source));
+        script->object = qPersistentNew<v8::Object>(workerEngine->contextWrapper()->urlScope(script->source));
 
         workerEngine->contextWrapper()->setReadOnly(script->object, false);
 
@@ -491,7 +491,7 @@ QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
 
 QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
 {
-    object.Dispose(); object.Clear();
+    qPersistentDispose(object);
 }
 
 int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
index 47f0fff..22ff408 100644 (file)
@@ -133,16 +133,16 @@ QDeclarativeXMLHttpRequestData::QDeclarativeXMLHttpRequestData()
 
 QDeclarativeXMLHttpRequestData::~QDeclarativeXMLHttpRequestData()
 {
-    nodeFunction.Dispose(); nodeFunction.Clear();
-    namedNodeMapPrototype.Dispose(); namedNodeMapPrototype.Clear();
-    nodeListPrototype.Dispose(); nodeListPrototype.Clear();
-    nodePrototype.Dispose(); nodePrototype.Clear();
-    elementPrototype.Dispose(); elementPrototype.Clear();
-    attrPrototype.Dispose(); attrPrototype.Clear();
-    characterDataPrototype.Dispose(); characterDataPrototype.Clear();
-    textPrototype.Dispose(); textPrototype.Clear();
-    cdataPrototype.Dispose(); cdataPrototype.Clear();
-    documentPrototype.Dispose(); documentPrototype.Clear();
+    qPersistentDispose(nodeFunction);
+    qPersistentDispose(namedNodeMapPrototype);
+    qPersistentDispose(nodeListPrototype);
+    qPersistentDispose(nodePrototype);
+    qPersistentDispose(elementPrototype);
+    qPersistentDispose(attrPrototype);
+    qPersistentDispose(characterDataPrototype);
+    qPersistentDispose(textPrototype);
+    qPersistentDispose(cdataPrototype);
+    qPersistentDispose(documentPrototype);
 }
 
 v8::Local<v8::Object> QDeclarativeXMLHttpRequestData::newNode()
@@ -150,7 +150,7 @@ v8::Local<v8::Object> QDeclarativeXMLHttpRequestData::newNode()
     if (nodeFunction.IsEmpty()) {
         v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
         ft->InstanceTemplate()->SetHasExternalResource(true);
-        nodeFunction = v8::Persistent<v8::Function>::New(ft->GetFunction());
+        nodeFunction = qPersistentNew<v8::Function>(ft->GetFunction());
     }
 
     return nodeFunction->NewInstance();
@@ -515,7 +515,7 @@ v8::Handle<v8::Object> Node::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->nodePrototype.IsEmpty()) {
-        d->nodePrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->nodePrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->nodePrototype->SetAccessor(v8::String::New("nodeName"), nodeName,
                                       0, v8::External::Wrap(engine));
         d->nodePrototype->SetAccessor(v8::String::New("nodeValue"), nodeValue,
@@ -582,7 +582,7 @@ v8::Handle<v8::Object> Element::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->elementPrototype.IsEmpty()) {
-        d->elementPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->elementPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->elementPrototype->SetPrototype(Node::prototype(engine));
         d->elementPrototype->SetAccessor(v8::String::New("tagName"), nodeName,
                                          0, v8::External::Wrap(engine));
@@ -595,7 +595,7 @@ v8::Handle<v8::Object> Attr::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->attrPrototype.IsEmpty()) {
-        d->attrPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->attrPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->attrPrototype->SetPrototype(Node::prototype(engine));
         d->attrPrototype->SetAccessor(v8::String::New("name"), name,
                                       0, v8::External::Wrap(engine));
@@ -648,7 +648,7 @@ v8::Handle<v8::Object> CharacterData::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->characterDataPrototype.IsEmpty()) {
-        d->characterDataPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->characterDataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->characterDataPrototype->SetPrototype(Node::prototype(engine));
         d->characterDataPrototype->SetAccessor(v8::String::New("data"), nodeValue,
                                                0, v8::External::Wrap(engine));
@@ -681,7 +681,7 @@ v8::Handle<v8::Object> Text::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->textPrototype.IsEmpty()) {
-        d->textPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->textPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->textPrototype->SetPrototype(CharacterData::prototype(engine));
         d->textPrototype->SetAccessor(v8::String::New("isElementContentWhitespace"), isElementContentWhitespace,
                                                0, v8::External::Wrap(engine));
@@ -696,7 +696,7 @@ v8::Handle<v8::Object> CDATA::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->cdataPrototype.IsEmpty()) {
-        d->cdataPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->cdataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->cdataPrototype->SetPrototype(Text::prototype(engine));
         // XXX freeze
     }
@@ -707,7 +707,7 @@ v8::Handle<v8::Object> Document::prototype(QV8Engine *engine)
 {
     QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
     if (d->documentPrototype.IsEmpty()) {
-        d->documentPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+        d->documentPrototype = qPersistentNew<v8::Object>(v8::Object::New());
         d->documentPrototype->SetPrototype(Node::prototype(engine));
         d->documentPrototype->SetAccessor(v8::String::New("xmlVersion"), xmlVersion, 
                                           0, v8::External::Wrap(engine));
@@ -878,7 +878,7 @@ v8::Handle<v8::Object> NamedNodeMap::prototype(QV8Engine *engine)
         ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
         ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
         ot->SetFallbackPropertyHandler(named, 0, 0, 0, 0, v8::External::Wrap(engine));
-        d->namedNodeMapPrototype = v8::Persistent<v8::Object>::New(ot->NewInstance());
+        d->namedNodeMapPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
         // XXX freeze
     }
     return d->namedNodeMapPrototype;
@@ -927,7 +927,7 @@ v8::Handle<v8::Object> NodeList::prototype(QV8Engine *engine)
         v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
         ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
         ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
-        d->nodeListPrototype = v8::Persistent<v8::Object>::New(ot->NewInstance());
+        d->nodeListPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
         // XXX freeze
     }
     return d->nodeListPrototype;
@@ -1259,11 +1259,10 @@ v8::Handle<v8::Object> QDeclarativeXMLHttpRequest::getMe() const
 
 void QDeclarativeXMLHttpRequest::setMe(v8::Handle<v8::Object> me)
 {
-    m_me.Dispose();
-    m_me = v8::Persistent<v8::Object>();
+    qPersistentDispose(m_me);
 
     if (!me.IsEmpty()) 
-        m_me = v8::Persistent<v8::Object>::New(me);
+        m_me = qPersistentNew<v8::Object>(me);
 }
 
 void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
index 1af4b4c..27002c6 100644 (file)
@@ -123,8 +123,8 @@ QV8ContextWrapper::~QV8ContextWrapper()
 
 void QV8ContextWrapper::destroy()
 {
-    m_urlConstructor.Dispose(); m_urlConstructor.Clear();
-    m_constructor.Dispose(); m_constructor.Clear();
+    qPersistentDispose(m_urlConstructor);
+    qPersistentDispose(m_constructor);
 }
 
 void QV8ContextWrapper::init(QV8Engine *engine)
@@ -134,13 +134,13 @@ void QV8ContextWrapper::init(QV8Engine *engine)
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetHasExternalResource(true);
     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
     {
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetHasExternalResource(true);
     ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
-    m_urlConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_urlConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
 }
 
index 693c8aa..530c9b0 100644 (file)
@@ -80,8 +80,7 @@ QV8Engine::~QV8Engine()
     delete m_listModelData;
     m_listModelData = 0;
 
-    m_getOwnPropertyNames.Dispose(); m_getOwnPropertyNames.Clear();
-    
+    qPersistentDispose(m_getOwnPropertyNames);
     m_valueTypeWrapper.destroy();
     m_variantWrapper.destroy();
     m_listWrapper.destroy();
@@ -89,8 +88,7 @@ QV8Engine::~QV8Engine()
     m_qobjectWrapper.destroy();
     m_contextWrapper.destroy();
     m_stringWrapper.destroy();
-    m_context.Dispose();
-    m_context.Clear();
+    qPersistentDispose(m_context);
 }
 
 void QV8Engine::init(QDeclarativeEngine *engine)
@@ -103,6 +101,7 @@ void QV8Engine::init(QDeclarativeEngine *engine)
 
     v8::HandleScope handle_scope;
     m_context = v8::Context::New();
+    qPersistentRegister(m_context);
     v8::Context::Scope context_scope(m_context);
 
     m_stringWrapper.init();
@@ -115,7 +114,7 @@ void QV8Engine::init(QDeclarativeEngine *engine)
 
     {
     v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
-    m_getOwnPropertyNames = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(v));
+    m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v));
     }
 
     initializeGlobal(m_context->Global());
@@ -615,6 +614,43 @@ void QV8Engine::gc()
     while (!v8::V8::IdleNotification()) {}
 }
 
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+#include <QtCore/qthreadstorage.h>
+static QThreadStorage<QSet<void *> *> QV8Engine_activeHandles;
+
+void QV8Engine::registerHandle(void *handle)
+{
+    if (!handle) {
+        qWarning("Attempting to register a null handle");
+        return;
+    }
+
+    if (!QV8Engine_activeHandles.hasLocalData()) 
+        QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+    if (QV8Engine_activeHandles.localData()->contains(handle)) {
+        qFatal("Handle %p already alive", handle);
+    } else {
+        QV8Engine_activeHandles.localData()->insert(handle);
+    }
+}
+
+void QV8Engine::releaseHandle(void *handle)
+{
+    if (!handle)
+        return;
+
+    if (!QV8Engine_activeHandles.hasLocalData()) 
+        QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+    if (QV8Engine_activeHandles.localData()->contains(handle)) {
+        QV8Engine_activeHandles.localData()->remove(handle);
+    } else {
+        qFatal("Handle %p already dead", handle);
+    }
+}
+#endif
+
 v8::Handle<v8::Value> QV8Engine::gc(const v8::Arguments &args)
 {
     gc();
index 5810b3e..ee0b911 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
+
+// Uncomment the following line to enable global handle debugging.  When enabled, all the persistent
+// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
+// with qPersistentDispose() are tracked.  If you try and do something illegal, like double disposing
+// a handle, qFatal() is called.
+// #define QML_GLOBAL_HANDLE_DEBUGGING
+
 #define V8_RESOURCE_TYPE(resourcetype) \
 public: \
     enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
@@ -240,6 +247,12 @@ public:
 
     static void gc();
 
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    // Used for handle debugging
+    static void registerHandle(void *);
+    static void releaseHandle(void *);
+#endif
+
 private:
     QDeclarativeEngine *m_engine;
     v8::Persistent<v8::Context> m_context;
@@ -294,6 +307,42 @@ private:
     QDateTime qtDateTimeFromJsDate(double jsDate);
 };
 
+// Allocate a new Persistent handle.  *ALL* persistent handles in QML must be allocated
+// using this method.
+template<class T>
+v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
+{
+    v8::Persistent<T> rv = v8::Persistent<T>::New(that);
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::registerHandle(*rv);
+#endif
+    return rv;
+}
+
+// Register a Persistent handle that was returned to you by V8 (such as by
+// v8::Context::New). This allows us to do handle tracking on these handles too.
+template<class T>
+void qPersistentRegister(v8::Persistent<T> handle)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::registerHandle(*handle);
+#else
+    Q_UNUSED(handle);
+#endif
+}
+
+// Dispose and clear a persistent handle.  *ALL* persistent handles in QML must be
+// disposed using this method.
+template<class T>
+void qPersistentDispose(v8::Persistent<T> &that)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::releaseHandle(*that);
+#endif
+    that.Dispose();
+    that.Clear();
+}
+
 QString QV8Engine::toString(v8::Handle<v8::Value> string)
 {
     return m_stringWrapper.toString(string->ToString());
index f2b25e0..3b8a081 100644 (file)
@@ -54,11 +54,11 @@ QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QDeclarativeContextDa
                        v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
 : m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
 {
-    m_qmlglobal = v8::Persistent<v8::Object>::New(qmlglobal);
+    m_qmlglobal = qPersistentNew<v8::Object>(qmlglobal);
     if (!callback.IsEmpty())
-        m_callbackFunction = v8::Persistent<v8::Function>::New(callback);
+        m_callbackFunction = qPersistentNew<v8::Function>(callback);
 
-    m_resultObject = v8::Persistent<v8::Object>::New(resultValue());
+    m_resultObject = qPersistentNew<v8::Object>(resultValue());
 
     m_network = engine->networkAccessManager();
 
@@ -72,8 +72,8 @@ QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QDeclarativeContextDa
 QV8Include::~QV8Include()
 {
     delete m_reply; m_reply = 0;
-    m_callbackFunction.Dispose();
-    m_resultObject.Dispose();
+    qPersistentDispose(m_callbackFunction);
+    qPersistentDispose(m_resultObject);
 }
 
 v8::Local<v8::Object> QV8Include::resultValue(Status status)
index 9e1110f..13b3b30 100644 (file)
@@ -75,12 +75,12 @@ void QV8ListWrapper::init(QV8Engine *engine)
                                         v8::Handle<v8::Value>(), v8::DEFAULT, 
                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
 }
 
 void QV8ListWrapper::destroy()
 {
-    m_constructor.Dispose();
+    qPersistentDispose(m_constructor);
 }
 
 v8::Handle<v8::Value> QV8ListWrapper::newList(QObject *object, int propId, int propType)
index 9ac482e..75a97ac 100644 (file)
@@ -93,8 +93,7 @@ public:
 
     ~QV8QObjectInstance()
     {
-        v8object.Dispose();
-        v8object.Clear();
+        qPersistentDispose(v8object);
     }
 
     virtual void objectDestroyed(QObject *o)
@@ -156,11 +155,11 @@ void QV8QObjectWrapper::destroy()
     qDeleteAll(m_connections);
     m_connections.clear();
 
-    m_hiddenObject.Dispose(); m_hiddenObject.Clear();
-    m_destroySymbol.Dispose(); m_destroySymbol.Clear();
-    m_toStringSymbol.Dispose(); m_toStringSymbol.Clear();
-    m_methodConstructor.Dispose(); m_methodConstructor.Clear();
-    m_constructor.Dispose(); m_constructor.Clear();
+    qPersistentDispose(m_hiddenObject);
+    qPersistentDispose(m_destroySymbol);
+    qPersistentDispose(m_toStringSymbol);
+    qPersistentDispose(m_methodConstructor);
+    qPersistentDispose(m_constructor);
 }
 
 #define FAST_VALUE_GETTER(name, cpptype, defaultvalue, constructor) \
@@ -204,15 +203,15 @@ void QV8QObjectWrapper::init(QV8Engine *engine)
 {
     m_engine = engine;
 
-    m_toStringSymbol = v8::Persistent<v8::String>::New(v8::String::NewSymbol("toString"));
-    m_destroySymbol = v8::Persistent<v8::String>::New(v8::String::NewSymbol("destroy"));
-    m_hiddenObject = v8::Persistent<v8::Object>::New(v8::Object::New());
+    m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
+    m_destroySymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("destroy"));
+    m_hiddenObject = qPersistentNew<v8::Object>(v8::Object::New());
 
     {
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
     {
     v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions
@@ -221,7 +220,7 @@ void QV8QObjectWrapper::init(QV8Engine *engine)
     v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction();
     v8::Handle<v8::Value> args[] = { invokeFn };
     v8::Local<v8::Function> createFn = v8::Local<v8::Function>::Cast(fn->Call(engine->global(), 1, args));
-    m_methodConstructor = v8::Persistent<v8::Function>::New(createFn);
+    m_methodConstructor = qPersistentNew<v8::Function>(createFn);
     }
 
     {
@@ -656,15 +655,14 @@ static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void
         }
     }
 
-    handle.Dispose();
+    qPersistentDispose(handle);
 }
 
 static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *data)
 {
     QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
     instance->v8object.Clear();
-    handle.Dispose();
-    handle.Clear();
+    qPersistentDispose(handle);
 }
 
 v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
@@ -735,7 +733,7 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
         }
 
         if (ft.IsEmpty()) {
-            constructor = v8::Persistent<v8::Function>::New(engine->qobjectWrapper()->m_constructor);
+            constructor = qPersistentNew<v8::Function>(engine->qobjectWrapper()->m_constructor);
         } else {
             ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter, 
                                                                QV8QObjectWrapper::Setter,
@@ -743,7 +741,7 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
                                                                0,
                                                                QV8QObjectWrapper::Enumerator);
             ft->InstanceTemplate()->SetHasExternalResource(true);
-            constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+            constructor = qPersistentNew<v8::Function>(ft->GetFunction());
         }
     }
 
@@ -806,7 +804,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
                 !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
 
         v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
-        ddata->v8object = v8::Persistent<v8::Object>::New(rv);
+        ddata->v8object = qPersistentNew<v8::Object>(rv);
         ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
         ddata->v8objectid = m_id;
         return rv;
@@ -822,7 +820,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
         // a handle in the ddata, we can assume ownership of the ddata->v8object
         if ((!found || (*iter)->v8object.IsEmpty()) && ddata->v8object.IsEmpty()) {
             v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
-            ddata->v8object = v8::Persistent<v8::Object>::New(rv);
+            ddata->v8object = qPersistentNew<v8::Object>(rv);
             ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
             ddata->v8objectid = m_id;
 
@@ -840,7 +838,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
 
         if ((*iter)->v8object.IsEmpty()) {
             v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
-            (*iter)->v8object = v8::Persistent<v8::Object>::New(rv);
+            (*iter)->v8object = qPersistentNew<v8::Object>(rv);
             (*iter)->v8object.MakeWeak((*iter), WeakQObjectInstanceCallback);
         }
 
@@ -897,10 +895,8 @@ QV8QObjectConnectionList::~QV8QObjectConnectionList()
     for (SlotHash::Iterator iter = slotHash.begin(); iter != slotHash.end(); ++iter) {
         QList<Connection> &connections = *iter;
         for (int ii = 0; ii < connections.count(); ++ii) {
-            connections[ii].thisObject.Dispose();
-            connections[ii].function.Dispose();
-            connections[ii].thisObject.Clear();
-            connections[ii].function.Clear();
+            qPersistentDispose(connections[ii].thisObject);
+            qPersistentDispose(connections[ii].function);
         }
     }
     slotHash.clear();
@@ -1010,8 +1006,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
 
     QV8QObjectConnectionList::Connection connection;
     if (!functionThisValue.IsEmpty()) 
-        connection.thisObject = v8::Persistent<v8::Object>::New(functionThisValue->ToObject());
-    connection.function = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(functionValue));
+        connection.thisObject = qPersistentNew<v8::Object>(functionThisValue->ToObject());
+    connection.function = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(functionValue));
 
     slotIter->append(connection);
 
@@ -1084,10 +1080,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
                 QPair<QObject *, int> connectedFunctionData = ExtractQtMethod(engine, connection.function);
                 if (connectedFunctionData == functionData) {
                     // Match!
-                    connection.thisObject.Dispose();
-                    connection.function.Dispose();
-                    connection.thisObject.Clear();
-                    connection.function.Clear();
+                    qPersistentDispose(connection.thisObject);
+                    qPersistentDispose(connection.function);
                     connections.removeAt(ii);
                     return v8::Undefined();
                 }
@@ -1102,10 +1096,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
                 connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
                 (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
                 // Match!
-                connection.thisObject.Dispose();
-                connection.function.Dispose();
-                connection.thisObject.Clear();
-                connection.function.Clear();
+                qPersistentDispose(connection.thisObject);
+                qPersistentDispose(connection.function);
                 connections.removeAt(ii);
                 return v8::Undefined();
             }
index 2067f73..b4a510e 100644 (file)
@@ -83,7 +83,7 @@ QV8TypeWrapper::~QV8TypeWrapper()
 
 void QV8TypeWrapper::destroy()
 {
-    m_constructor.Dispose();
+    qPersistentDispose(m_constructor);
 }
 
 void QV8TypeWrapper::init(QV8Engine *engine)
@@ -92,7 +92,7 @@ void QV8TypeWrapper::init(QV8Engine *engine)
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
 }
 
 v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeType *t, TypeNameMode mode)
index 6dfb431..b16a81e 100644 (file)
@@ -103,7 +103,7 @@ QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
 
 void QV8ValueTypeWrapper::destroy()
 {
-    m_constructor.Dispose();
+    qPersistentDispose(m_constructor);
 }
 
 void QV8ValueTypeWrapper::init(QV8Engine *engine)
@@ -112,7 +112,7 @@ void QV8ValueTypeWrapper::init(QV8Engine *engine)
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
 }
 
 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
index de3cb11..ef1f972 100644 (file)
@@ -74,11 +74,11 @@ void QV8VariantWrapper::init(QV8Engine *engine)
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
     {
-    m_preserve = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(Preserve)->GetFunction());
-    m_destroy = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(Destroy)->GetFunction());
+    m_preserve = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Preserve)->GetFunction());
+    m_destroy = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Destroy)->GetFunction());
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
     ft->InstanceTemplate()->SetHasExternalResource(true);
@@ -88,17 +88,17 @@ void QV8VariantWrapper::init(QV8Engine *engine)
     ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0, 
                                         m_destroy, v8::DEFAULT, 
                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
-    m_scarceConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
     }
 
 }
 
 void QV8VariantWrapper::destroy()
 {
-    m_destroy.Dispose(); m_destroy.Clear();
-    m_preserve.Dispose(); m_preserve.Clear();
-    m_scarceConstructor.Dispose(); m_scarceConstructor.Clear();
-    m_constructor.Dispose(); m_constructor.Clear();
+    qPersistentDispose(m_destroy);
+    qPersistentDispose(m_preserve);
+    qPersistentDispose(m_scarceConstructor);
+    qPersistentDispose(m_constructor);
 }
 
 v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
index 1f26140..d4af0b1 100644 (file)
@@ -102,12 +102,12 @@ QDeclarativeListModelV8Data::QDeclarativeListModelV8Data()
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
     ft->InstanceTemplate()->SetHasExternalResource(true);
-    constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+    constructor = qPersistentNew<v8::Function>(ft->GetFunction());
 }
 
 QDeclarativeListModelV8Data::~QDeclarativeListModelV8Data()
 {
-    constructor.Dispose(); constructor.Clear();
+    qPersistentDispose(constructor);
 }
 
 v8::Handle<v8::Value> QDeclarativeListModelV8Data::Getter(v8::Local<v8::String> property,