aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-09-05 17:31:41 +1000
committerQt by Nokia <qt-info@nokia.com>2011-09-29 06:12:49 +0200
commit703c808a5649169dd6b9605af273374cd62951d1 (patch)
tree7248cc72bfa632a51c814d6622f0b12a7f2bd443
parent600e56ad053362dd5d4150f5dec6b93c2fee575b (diff)
Asynchronous component instantiation
This introduces two main: * the QML compiler executes in a separate thread * item instantiation can be interrupted and resumed to allow it to be split across multiple frames. Task-number: QTBUG-21151 Change-Id: I9631c62bb77da3a2e0c37f0da3719533fdce4fef Reviewed-on: http://codereview.qt-project.org/5676 Reviewed-by: Martin Jones <martin.jones@nokia.com>
-rw-r--r--src/declarative/qml/ftw/ftw.pri4
-rw-r--r--src/declarative/qml/ftw/qdeclarativerefcount_p.h58
-rw-r--r--src/declarative/qml/ftw/qdeclarativethread.cpp359
-rw-r--r--src/declarative/qml/ftw/qdeclarativethread_p.h318
-rw-r--r--src/declarative/qml/ftw/qfieldlist_p.h29
-rw-r--r--src/declarative/qml/ftw/qfinitestack_p.h186
-rw-r--r--src/declarative/qml/qdeclarativecleanup.cpp41
-rw-r--r--src/declarative/qml/qdeclarativecleanup_p.h6
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp31
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp162
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h39
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp877
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h13
-rw-r--r--src/declarative/qml/qdeclarativecomponent_p.h19
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp16
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h5
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp148
-rw-r--r--src/declarative/qml/qdeclarativeengine.h7
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h272
-rw-r--r--src/declarative/qml/qdeclarativeextensioninterface.h10
-rw-r--r--src/declarative/qml/qdeclarativeextensionplugin.h4
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp30
-rw-r--r--src/declarative/qml/qdeclarativeimport_p.h1
-rw-r--r--src/declarative/qml/qdeclarativeincubator.cpp327
-rw-r--r--src/declarative/qml/qdeclarativeincubator.h130
-rw-r--r--src/declarative/qml/qdeclarativeincubator_p.h (renamed from src/declarative/qml/ftw/qdeclarativerefcount.cpp)64
-rw-r--r--src/declarative/qml/qdeclarativeinstruction.cpp15
-rw-r--r--src/declarative/qml/qdeclarativeinstruction_p.h33
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp17
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h2
-rw-r--r--src/declarative/qml/qdeclarativescript.cpp2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp581
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h106
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp11
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h7
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp802
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h128
-rw-r--r--src/declarative/qml/qml.pri3
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp8
-rw-r--r--src/declarative/qml/v8/qv8engine_p.h3
-rw-r--r--src/declarative/qml/v8/qv8qobjectwrapper.cpp3
-rw-r--r--src/declarative/util/qdeclarativeanimation.cpp2
-rw-r--r--src/declarative/util/qdeclarativebehavior.cpp2
-rw-r--r--src/qtquick1/util/qdeclarativeanimation.cpp2
-rw-r--r--src/qtquick1/util/qdeclarativebehavior.cpp2
-rw-r--r--tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp16
46 files changed, 3807 insertions, 1094 deletions
diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri
index d6e7df53b2..2d6729bd79 100644
--- a/src/declarative/qml/ftw/ftw.pri
+++ b/src/declarative/qml/ftw/ftw.pri
@@ -11,12 +11,14 @@ HEADERS += \
$$PWD/qfieldlist_p.h \
$$PWD/qfastmetabuilder_p.h \
$$PWD/qhashfield_p.h \
+ $$PWD/qdeclarativethread_p.h \
+ $$PWD/qfinitestack_p.h \
SOURCES += \
$$PWD/qintrusivelist.cpp \
$$PWD/qmetaobjectbuilder.cpp \
$$PWD/qhashedstring.cpp \
- $$PWD/qdeclarativerefcount.cpp \
$$PWD/qdeclarativepool.cpp \
$$PWD/qfastmetabuilder.cpp \
+ $$PWD/qdeclarativethread.cpp \
diff --git a/src/declarative/qml/ftw/qdeclarativerefcount_p.h b/src/declarative/qml/ftw/qdeclarativerefcount_p.h
index 381327098c..8ae9618f30 100644
--- a/src/declarative/qml/ftw/qdeclarativerefcount_p.h
+++ b/src/declarative/qml/ftw/qdeclarativerefcount_p.h
@@ -54,6 +54,7 @@
//
#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
QT_BEGIN_HEADER
@@ -61,16 +62,19 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
-class Q_DECLARATIVE_EXPORT QDeclarativeRefCount
+class QDeclarativeRefCount
{
public:
- QDeclarativeRefCount();
- virtual ~QDeclarativeRefCount();
- void addref();
- void release();
+ inline QDeclarativeRefCount();
+ inline virtual ~QDeclarativeRefCount();
+ inline void addref();
+ inline void release();
+
+protected:
+ inline virtual void destroy();
private:
- int refCount;
+ QAtomicInt refCount;
};
template<class T>
@@ -92,10 +96,40 @@ public:
inline operator T*() const { return o; }
inline T* data() const { return o; }
+ inline QDeclarativeRefPointer<T> &take(T *);
+
private:
T *o;
};
+QDeclarativeRefCount::QDeclarativeRefCount()
+: refCount(1)
+{
+}
+
+QDeclarativeRefCount::~QDeclarativeRefCount()
+{
+ Q_ASSERT(refCount == 0);
+}
+
+void QDeclarativeRefCount::addref()
+{
+ Q_ASSERT(refCount > 0);
+ refCount.ref();
+}
+
+void QDeclarativeRefCount::release()
+{
+ Q_ASSERT(refCount > 0);
+ if (!refCount.deref())
+ destroy();
+}
+
+void QDeclarativeRefCount::destroy()
+{
+ delete this;
+}
+
template<class T>
QDeclarativeRefPointer<T>::QDeclarativeRefPointer()
: o(0)
@@ -140,6 +174,18 @@ QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::operator=(T *other)
return *this;
}
+/*!
+Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
+of the callers reference of other.
+*/
+template<class T>
+QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::take(T *other)
+{
+ if (o) o->release();
+ o = other;
+ return *this;
+}
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/declarative/qml/ftw/qdeclarativethread.cpp b/src/declarative/qml/ftw/qdeclarativethread.cpp
new file mode 100644
index 0000000000..4a21c90bf1
--- /dev/null
+++ b/src/declarative/qml/ftw/qdeclarativethread.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativethread_p.h"
+
+#include <private/qfieldlist_p.h>
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeThreadPrivate : public QThread
+{
+public:
+ QDeclarativeThreadPrivate(QDeclarativeThread *);
+ QDeclarativeThread *q;
+
+ virtual void run();
+
+ inline void lock() { _mutex.lock(); }
+ inline void unlock() { _mutex.unlock(); }
+ inline void wait() { _wait.wait(&_mutex); }
+ inline void wakeOne() { _wait.wakeOne(); }
+ inline void wakeAll() { _wait.wakeAll(); }
+
+ quint32 m_threadProcessing:1; // Set when the thread is processing messages
+ quint32 m_mainProcessing:1; // Set when the main thread is processing messages
+ quint32 m_shutdown:1; // Set by main thread to request a shutdown
+ quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+
+ typedef QFieldList<QDeclarativeThread::Message, &QDeclarativeThread::Message::next> MessageList;
+ MessageList threadList;
+ MessageList mainList;
+
+ QDeclarativeThread::Message *mainSync;
+
+ void triggerMainEvent();
+ void triggerThreadEvent();
+
+ void mainEvent();
+ void threadEvent();
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ struct MainObject : public QObject {
+ MainObject(QDeclarativeThreadPrivate *p);
+ virtual bool event(QEvent *e);
+ QDeclarativeThreadPrivate *p;
+ };
+ MainObject m_mainObject;
+
+ QMutex _mutex;
+ QWaitCondition _wait;
+};
+
+QDeclarativeThreadPrivate::MainObject::MainObject(QDeclarativeThreadPrivate *p)
+: p(p)
+{
+}
+
+// Trigger mainEvent in main thread. Must be called from thread.
+void QDeclarativeThreadPrivate::triggerMainEvent()
+{
+ Q_ASSERT(q->isThisThread());
+ QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User));
+}
+
+// Trigger even in thread. Must be called from main thread.
+void QDeclarativeThreadPrivate::triggerThreadEvent()
+{
+ Q_ASSERT(!q->isThisThread());
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+bool QDeclarativeThreadPrivate::MainObject::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ p->mainEvent();
+ return QObject::event(e);
+}
+
+QDeclarativeThreadPrivate::QDeclarativeThreadPrivate(QDeclarativeThread *q)
+: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
+ m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
+{
+}
+
+bool QDeclarativeThreadPrivate::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ threadEvent();
+ return QThread::event(e);
+}
+
+void QDeclarativeThreadPrivate::run()
+{
+ lock();
+
+ wakeOne();
+
+ unlock();
+
+ q->startupThread();
+ exec();
+}
+
+void QDeclarativeThreadPrivate::mainEvent()
+{
+ lock();
+
+ m_mainProcessing = true;
+
+ while (!mainList.isEmpty() || mainSync) {
+ bool isSync = mainSync != 0;
+ QDeclarativeThread::Message *message = isSync?mainSync:mainList.takeFirst();
+ unlock();
+
+ message->call(q);
+ delete message;
+
+ lock();
+
+ if (isSync) {
+ mainSync = 0;
+ wakeOne();
+ }
+ }
+
+ m_mainProcessing = false;
+
+ unlock();
+}
+
+void QDeclarativeThreadPrivate::threadEvent()
+{
+ lock();
+
+ if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+ q->shutdownThread();
+ } else {
+ m_threadProcessing = true;
+
+ while (!threadList.isEmpty()) {
+ QDeclarativeThread::Message *message = threadList.first();
+
+ unlock();
+
+ message->call(q);
+
+ lock();
+
+ delete threadList.takeFirst();
+ }
+
+ wakeOne();
+
+ m_threadProcessing = false;
+
+ unlock();
+ }
+}
+
+QDeclarativeThread::QDeclarativeThread()
+: d(new QDeclarativeThreadPrivate(this))
+{
+ d->lock();
+ d->start();
+ d->wait();
+ d->unlock();
+ d->moveToThread(d);
+
+}
+
+QDeclarativeThread::~QDeclarativeThread()
+{
+ delete d;
+}
+
+void QDeclarativeThread::shutdown()
+{
+ d->lock();
+ Q_ASSERT(!d->m_shutdown);
+ d->m_shutdown = true;
+ if (d->threadList.isEmpty() && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->wait();
+ d->unlock();
+ d->QThread::wait();
+}
+
+void QDeclarativeThread::lock()
+{
+ d->lock();
+}
+
+void QDeclarativeThread::unlock()
+{
+ d->unlock();
+}
+
+void QDeclarativeThread::wakeOne()
+{
+ d->wakeOne();
+}
+
+void QDeclarativeThread::wakeAll()
+{
+ d->wakeAll();
+}
+
+void QDeclarativeThread::wait()
+{
+ d->wait();
+}
+
+bool QDeclarativeThread::isThisThread() const
+{
+ return QThread::currentThread() == d;
+}
+
+QThread *QDeclarativeThread::thread() const
+{
+ return const_cast<QThread *>(static_cast<const QThread *>(d));
+}
+
+// Called when the thread starts. Do startup stuff in here.
+void QDeclarativeThread::startupThread()
+{
+}
+
+// Called when the thread shuts down. Do cleanup in here.
+void QDeclarativeThread::shutdownThread()
+{
+}
+
+void QDeclarativeThread::internalCallMethodInThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ Q_ASSERT(d->m_mainThreadWaiting == false);
+
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+
+ d->m_mainThreadWaiting = true;
+
+ do {
+ if (d->mainSync) {
+ QDeclarativeThread::Message *message = d->mainSync;
+ unlock();
+ message->call(this);
+ delete message;
+ lock();
+ d->mainSync = 0;
+ wakeOne();
+ } else {
+ d->wait();
+ }
+ } while (d->mainSync || !d->threadList.isEmpty());
+
+ d->m_mainThreadWaiting = false;
+ d->unlock();
+}
+
+void QDeclarativeThread::internalCallMethodInMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+
+ d->lock();
+
+ Q_ASSERT(d->mainSync == 0);
+ d->mainSync = message;
+
+ if (d->m_mainThreadWaiting) {
+ d->wakeOne();
+ } else if (d->m_mainProcessing) {
+ // Do nothing - it is already looping
+ } else {
+ d->triggerMainEvent();
+ }
+
+ while (d->mainSync && !d->m_shutdown)
+ d->wait();
+
+ d->unlock();
+}
+
+void QDeclarativeThread::internalPostMethodToThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->unlock();
+}
+
+void QDeclarativeThread::internalPostMethodToMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+ d->lock();
+ bool wasEmpty = d->mainList.isEmpty();
+ d->mainList.append(message);
+ if (wasEmpty && d->m_mainProcessing == false)
+ d->triggerMainEvent();
+ d->unlock();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/ftw/qdeclarativethread_p.h b/src/declarative/qml/ftw/qdeclarativethread_p.h
new file mode 100644
index 0000000000..2f5815568e
--- /dev/null
+++ b/src/declarative/qml/ftw/qdeclarativethread_p.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVETHREAD_P_H
+#define QDECLARATIVETHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtCore/qglobal.h>
+
+#include <private/qintrusivelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+
+class QDeclarativeThreadPrivate;
+class QDeclarativeThread
+{
+public:
+ QDeclarativeThread();
+ virtual ~QDeclarativeThread();
+ void shutdown();
+
+ void lock();
+ void unlock();
+ void wakeOne();
+ void wakeAll();
+ void wait();
+
+ QThread *thread() const;
+ bool isThisThread() const;
+
+ // Synchronously invoke a method in the thread
+ template<class O>
+ inline void callMethodInThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Synchronously invoke a method in the main thread. If the main thread is
+ // blocked in a callMethodInThread() call, the call is made from within that
+ // call.
+ template<class O>
+ inline void callMethodInMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the thread.
+ template<class O>
+ inline void postMethodToThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the main thread.
+ template<class O>
+ inline void postMethodToMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+protected:
+ virtual void startupThread();
+ virtual void shutdownThread();
+
+private:
+ friend class QDeclarativeThreadPrivate;
+
+ struct Message {
+ Message() : next(0) {}
+ virtual ~Message() {}
+ Message *next;
+ virtual void call(QDeclarativeThread *) = 0;
+ };
+ void internalCallMethodInThread(Message *);
+ void internalCallMethodInMain(Message *);
+ void internalPostMethodToThread(Message *);
+ void internalPostMethodToMain(Message *);
+ QDeclarativeThreadPrivate *d;
+};
+
+template<class O>
+void QDeclarativeThread::callMethodInThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QDeclarativeThread::callMethodInThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QDeclarativeThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QDeclarativeThread::callMethodInMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QDeclarativeThread::callMethodInMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QDeclarativeThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QDeclarativeThread::postMethodToThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QDeclarativeThread::postMethodToThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QDeclarativeThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QDeclarativeThread::postMethodToMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QDeclarativeThread::postMethodToMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QDeclarativeThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QDeclarativeThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg, arg2));
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETHREAD_P_H
diff --git a/src/declarative/qml/ftw/qfieldlist_p.h b/src/declarative/qml/ftw/qfieldlist_p.h
index ff6b89b96f..f0efd16a20 100644
--- a/src/declarative/qml/ftw/qfieldlist_p.h
+++ b/src/declarative/qml/ftw/qfieldlist_p.h
@@ -61,6 +61,8 @@ class QFieldList
public:
inline QFieldList();
inline N *first() const;
+ inline N *takeFirst();
+
inline void append(N *);
inline void prepend(N *);
@@ -73,6 +75,8 @@ public:
inline void prepend(QFieldList<N, nextMember> &);
inline void insertAfter(N *, QFieldList<N, nextMember> &);
+ inline void copyAndClear(QFieldList<N, nextMember> &);
+
static inline N *next(N *v);
private:
@@ -94,6 +98,21 @@ N *QFieldList<N, nextMember>::first() const
}
template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::takeFirst()
+{
+ N *value = _first;
+ if (value) {
+ _first = next(value);
+ if (_last == value) {
+ Q_ASSERT(_first == 0);
+ _last = 0;
+ }
+ --_count;
+ }
+ return value;
+}
+
+template<class N, N *N::*nextMember>
void QFieldList<N, nextMember>::append(N *v)
{
Q_ASSERT(v->*nextMember == 0);
@@ -207,4 +226,14 @@ void QFieldList<N, nextMember>::insertAfter(N *after, QFieldList<N, nextMember>
}
}
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
+{
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ o._first = o._last = 0;
+ o._count = 0;
+}
+
#endif // QFIELDLIST_P_H
diff --git a/src/declarative/qml/ftw/qfinitestack_p.h b/src/declarative/qml/ftw/qfinitestack_p.h
new file mode 100644
index 0000000000..de9d833762
--- /dev/null
+++ b/src/declarative/qml/ftw/qfinitestack_p.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFINITESTACK_P_H
+#define QFINITESTACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+struct QFiniteStack {
+ inline QFiniteStack();
+ inline ~QFiniteStack();
+
+ inline void deallocate();
+ inline void allocate(int size);
+
+ inline bool isEmpty() const;
+ inline const T &top() const;
+ inline T &top();
+ inline void push(const T &o);
+ inline T pop();
+ inline int count() const;
+ inline const T &at(int index) const;
+ inline T &operator[](int index);
+private:
+ T *_array;
+ int _alloc;
+ int _size;
+};
+
+template<typename T>
+QFiniteStack<T>::QFiniteStack()
+: _array(0), _alloc(0), _size(0)
+{
+}
+
+template<typename T>
+QFiniteStack<T>::~QFiniteStack()
+{
+ deallocate();
+}
+
+template<typename T>
+bool QFiniteStack<T>::isEmpty() const
+{
+ return _size == 0;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::top() const
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+T &QFiniteStack<T>::top()
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+void QFiniteStack<T>::push(const T &o)
+{
+ if (QTypeInfo<T>::isComplex) {
+ new (_array + _size++) T(o);
+ } else {
+ _array[_size++] = o;
+ }
+}
+
+template<typename T>
+T QFiniteStack<T>::pop()
+{
+ --_size;
+
+ if (QTypeInfo<T>::isComplex) {
+ T rv = _array[_size];
+ (_array + _size)->~T();
+ return rv;
+ } else {
+ return _array[_size];
+ }
+}
+
+template<typename T>
+int QFiniteStack<T>::count() const
+{
+ return _size;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::at(int index) const
+{
+ return _array[index];
+}
+
+template<typename T>
+T &QFiniteStack<T>::operator[](int index)
+{
+ return _array[index];
+}
+
+template<typename T>
+void QFiniteStack<T>::allocate(int size)
+{
+ Q_ASSERT(_array == 0);
+ Q_ASSERT(_alloc == 0);
+ Q_ASSERT(_size == 0);
+
+ if (!size) return;
+
+ _array = (T *)qMalloc(size * sizeof(T));
+ _alloc = size;
+}
+
+template<typename T>
+void QFiniteStack<T>::deallocate()
+{
+ if (QTypeInfo<T>::isComplex) {
+ T *i = _array + _size;
+ while (i != _array)
+ (--i)->~T();
+ }
+
+ qFree(_array);
+
+ _array = 0;
+ _alloc = 0;
+ _size = 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QFINITESTACK_P_H
+
diff --git a/src/declarative/qml/qdeclarativecleanup.cpp b/src/declarative/qml/qdeclarativecleanup.cpp
index db671a392a..d0d368773b 100644
--- a/src/declarative/qml/qdeclarativecleanup.cpp
+++ b/src/declarative/qml/qdeclarativecleanup.cpp
@@ -50,22 +50,43 @@ QT_BEGIN_NAMESPACE
\class QDeclarativeCleanup
\brief The QDeclarativeCleanup provides a callback when a QDeclarativeEngine is deleted.
-Any object that needs cleanup to occur before the QDeclarativeEngine's QScriptEngine is
+Any object that needs cleanup to occur before the QDeclarativeEngine's V8 engine is
destroyed should inherit from QDeclarativeCleanup. The clear() virtual method will be
-called by QDeclarativeEngine just before it deletes the QScriptEngine.
+called by QDeclarativeEngine just before it destroys the context.
*/
-/*!
-\internal
+/*
+Create a QDeclarativeCleanup that is not associated with any engine.
+*/
+QDeclarativeCleanup::QDeclarativeCleanup()
+: prev(0), next(0), engine(0)
+{
+}
+
+/*!
Create a QDeclarativeCleanup for \a engine
*/
QDeclarativeCleanup::QDeclarativeCleanup(QDeclarativeEngine *engine)
-: prev(0), next(0)
+: prev(0), next(0), engine(0)
{
if (!engine)
return;
+ addToEngine(engine);
+}
+
+/*!
+Adds this object to \a engine's cleanup list. hasEngine() must be false
+before calling this method.
+*/
+void QDeclarativeCleanup::addToEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(QDeclarativeEnginePrivate::isEngineThread(engine));
+
+ this->engine = engine;
+
QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
if (p->cleanup) next = p->cleanup;
@@ -75,13 +96,23 @@ QDeclarativeCleanup::QDeclarativeCleanup(QDeclarativeEngine *engine)
}
/*!
+\fn bool QDeclarativeCleanup::hasEngine() const
+
+Returns true if this QDeclarativeCleanup is associated with an engine, otherwise false.
+*/
+
+/*!
\internal
*/
QDeclarativeCleanup::~QDeclarativeCleanup()
{
+ Q_ASSERT(!prev || engine);
+ Q_ASSERT(!prev || QDeclarativeEnginePrivate::isEngineThread(engine));
+
if (prev) *prev = next;
if (next) next->prev = prev;
prev = 0;
next = 0;
}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecleanup_p.h b/src/declarative/qml/qdeclarativecleanup_p.h
index 1efe564edc..272b0c81e5 100644
--- a/src/declarative/qml/qdeclarativecleanup_p.h
+++ b/src/declarative/qml/qdeclarativecleanup_p.h
@@ -63,9 +63,12 @@ class QDeclarativeEngine;
class Q_DECLARATIVE_EXPORT QDeclarativeCleanup
{
public:
+ QDeclarativeCleanup();
QDeclarativeCleanup(QDeclarativeEngine *);
virtual ~QDeclarativeCleanup();
+ bool hasEngine() const { return prev != 0; }
+ void addToEngine(QDeclarativeEngine *);
protected:
virtual void clear() = 0;
@@ -73,6 +76,9 @@ private:
friend class QDeclarativeEnginePrivate;
QDeclarativeCleanup **prev;
QDeclarativeCleanup *next;
+
+ // Only used for asserts
+ QDeclarativeEngine *engine;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
index a1bdca26fa..6815967f57 100644
--- a/src/declarative/qml/qdeclarativecompileddata.cpp
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -101,13 +101,25 @@ int QDeclarativeCompiledData::indexForUrl(const QUrl &data)
}
QDeclarativeCompiledData::QDeclarativeCompiledData(QDeclarativeEngine *engine)
-: QDeclarativeCleanup(engine), importCache(0), root(0), rootPropertyCache(0)
+: engine(engine), importCache(0), root(0), rootPropertyCache(0)
{
+ Q_ASSERT(engine);
+
bytecode.reserve(1024);
}
+void QDeclarativeCompiledData::destroy()
+{
+ if (engine && hasEngine())
+ QDeclarativeEnginePrivate::deleteInEngineThread(engine, this);
+ else
+ delete this;
+}
+
QDeclarativeCompiledData::~QDeclarativeCompiledData()
{
+ clear();
+
for (int ii = 0; ii < types.count(); ++ii) {
if (types.at(ii).component)
types.at(ii).component->release();
@@ -129,18 +141,13 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
if (rootPropertyCache)
rootPropertyCache->release();
-
- qDeleteAll(cachedClosures);
-
- for (int ii = 0; ii < v8bindings.count(); ++ii)
- qPersistentDispose(v8bindings[ii]);
}
void QDeclarativeCompiledData::clear()
{
- qDeleteAll(cachedClosures);
- for (int ii = 0; ii < cachedClosures.count(); ++ii)
- cachedClosures[ii] = 0;
+ for (int ii = 0; ii < v8bindings.count(); ++ii)
+ qPersistentDispose(v8bindings[ii]);
+ v8bindings.clear();
}
const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const
@@ -246,4 +253,10 @@ QDeclarativeInstruction::Type QDeclarativeCompiledData::instructionType(const QD
#endif
}
+void QDeclarativeCompiledData::initialize(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(!hasEngine());
+ QDeclarativeCleanup::addToEngine(engine);
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index fe0375fcff..8c26a3bfa6 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -650,7 +650,14 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
Q_ASSERT(out);
reset(out);
- output = out;
+ QDeclarativeScript::Object *root = unit->parser().tree();
+ Q_ASSERT(root);
+
+ this->engine = engine;
+ this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ this->unit = unit;
+ this->unitRoot = root;
+ this->output = out;
// Compile types
const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
@@ -673,12 +680,10 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
if (ref.type->containsRevisionedAttributes()) {
QDeclarativeError cacheError;
- ref.typePropertyCache =
- QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
-
- if (!ref.typePropertyCache) {
+ ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
+ cacheError);
+ if (!ref.typePropertyCache)
COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
- }
ref.typePropertyCache->addref();
}
@@ -689,13 +694,6 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
out->types << ref;
}
- QDeclarativeScript::Object *root = unit->parser().tree();
- Q_ASSERT(root);
-
- this->engine = engine;
- this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
- this->unit = unit;
- this->unitRoot = root;
compileTree(root);
if (!isError()) {
@@ -731,20 +729,12 @@ void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
importedScriptIndexes.append(script.qualifier);
-
- Instruction::StoreImportedScript import;
- import.value = output->scripts.count();
-
- QDeclarativeScriptData *scriptData = script.script->scriptData();
- scriptData->addref();
- output->scripts << scriptData;
- output->addInstruction(import);
}
// We generate the importCache before we build the tree so that
// it can be used in the binding compiler. Given we "expect" the
// QML compilation to succeed, this isn't a waste.
- output->importCache = new QDeclarativeTypeNameCache(engine);
+ output->importCache = new QDeclarativeTypeNameCache();
for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
output->importCache->add(importedScriptIndexes.at(ii), ii);
unit->imports().populateCache(output->importCache, engine);
@@ -753,15 +743,27 @@ void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
return;
Instruction::Init init;
- init.bindingsSize = compileState->bindings.count();
+ init.bindingsSize = compileState->totalBindingsCount;
init.parserStatusSize = compileState->parserStatusCount;
init.contextCache = genContextCache();
+ init.objectStackSize = compileState->objectDepth.maxDepth();
+ init.listStackSize = compileState->listDepth.maxDepth();
if (compileState->compiledBindingData.isEmpty())
init.compiledBinding = -1;
else
init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
output->addInstruction(init);
+ foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ Instruction::StoreImportedScript import;
+ import.value = output->scripts.count();
+
+ QDeclarativeScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ output->scripts << scriptData;
+ output->addInstruction(import);
+ }
+
if (!compileState->v8BindingProgram.isEmpty()) {
Instruction::InitV8Bindings bindings;
bindings.program = output->indexForString(compileState->v8BindingProgram);
@@ -805,8 +807,7 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const Bi
componentStats->componentStat.objects++;
Q_ASSERT (obj->type != -1);
- const QDeclarativeCompiledData::TypeReference &tr =
- output->types.at(obj->type);
+ const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
obj->metatype = tr.metaObject();
if (tr.type)
@@ -818,6 +819,20 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const Bi
return true;
}
+ if (tr.component) {
+ typedef QDeclarativeInstruction I;
+ const I *init = ((const I *)tr.component->bytecode.constData());
+ Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
+
+ // Adjust stack depths to include nested components
+ compileState->objectDepth.pushPop(init->init.objectStackSize);
+ compileState->listDepth.pushPop(init->init.listStackSize);
+ compileState->parserStatusCount += init->init.parserStatusSize;
+ compileState->totalBindingsCount += init->init.bindingsSize;
+ }
+
+ compileState->objectDepth.push();
+
// Object instantiations reset the binding context
BindingContext objCtxt(obj);
@@ -1006,6 +1021,8 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const Bi
}
}
+ compileState->objectDepth.pop();
+
return true;
}
@@ -1031,23 +1048,35 @@ void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
} else {
- Instruction::CreateObject create;
- create.line = obj->location.start.line;
- create.column = obj->location.start.column;
- create.data = -1;
- if (!obj->custom.isEmpty())
- create.data = output->indexForByteArray(obj->custom);
- create.type = obj->type;
- if (!output->types.at(create.type).type &&
- !obj->bindingBitmask.isEmpty()) {
- Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
- create.bindingBits =
- output->indexForByteArray(obj->bindingBitmask);
+ if (output->types.at(obj->type).type) {
+ Instruction::CreateCppObject create;
+ create.line = obj->location.start.line;
+ create.column = obj->location.start.column;
+ create.data = -1;
+ if (!obj->custom.isEmpty())
+ create.data = output->indexForByteArray(obj->custom);
+ create.type = obj->type;
+ create.isRoot = (compileState->root == obj);
+ output->addInstruction(create);
} else {
- create.bindingBits = -1;
- }
- output->addInstruction(create);
+ Instruction::CreateQMLObject create;
+ create.type = obj->type;
+ create.isRoot = (compileState->root == obj);
+ if (!obj->bindingBitmask.isEmpty()) {
+ Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
+ create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
+ } else {
+ create.bindingBits = -1;
+ }
+ output->addInstruction(create);
+
+ Instruction::CompleteQMLObject complete;
+ complete.line = obj->location.start.line;
+ complete.column = obj->location.start.column;
+ complete.isRoot = (compileState->root == obj);
+ output->addInstruction(complete);
+ }
}
// Setup the synthesized meta object if necessary
@@ -1132,12 +1161,13 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
int deferIdx = output->addInstruction(defer);
int nextInstructionIndex = output->nextInstructionIndex();
- Instruction::Init init;
- init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
- init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
- init.contextCache = -1;
- init.compiledBinding = -1;
- output->addInstruction(init);
+ Instruction::DeferInit dinit;
+ // XXX - these are now massive over allocations
+ dinit.bindingsSize = compileState->totalBindingsCount;
+ dinit.parserStatusSize = compileState->parserStatusCount;
+ dinit.objectStackSize = compileState->objectDepth.maxDepth();
+ dinit.listStackSize = compileState->listDepth.maxDepth();
+ output->addInstruction(dinit);
for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
if (!prop->isDeferred)
@@ -1269,6 +1299,7 @@ void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
create.line = root->location.start.line;
create.column = root->location.start.column;
create.endLine = root->location.end.line;
+ create.isRoot = (compileState->root == obj);
int createInstruction = output->addInstruction(create);
int nextInstructionIndex = output->nextInstructionIndex();
@@ -1276,9 +1307,11 @@ void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
compileState = componentState(root);
Instruction::Init init;
- init.bindingsSize = compileState->bindings.count();
+ init.bindingsSize = compileState->totalBindingsCount;
init.parserStatusSize = compileState->parserStatusCount;
init.contextCache = genContextCache();
+ init.objectStackSize = compileState->objectDepth.maxDepth();
+ init.listStackSize = compileState->listDepth.maxDepth();
if (compileState->compiledBindingData.isEmpty())
init.compiledBinding = -1;
else
@@ -1325,6 +1358,8 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
// The special "Component" element can only have the id property and a
// default property, that actually defines the component's tree
+ compileState->objectDepth.push();
+
// Find, check and set the "id" property (if any)
Property *idProp = 0;
if (obj->properties.isMany() ||
@@ -1371,6 +1406,8 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
// Build the component tree
COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
+ compileState->objectDepth.pop();
+
return true;
}
@@ -1849,6 +1886,7 @@ bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
{
+ Q_UNUSED(id);
Q_ASSERT(!compileState->ids.value(id));
Q_ASSERT(obj->id == id);
obj->idIndex = compileState->ids.count();
@@ -1859,6 +1897,7 @@ void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
{
Q_ASSERT(ref->value && !ref->value->bindingReference);
ref->value->bindingReference = ref;
+ compileState->totalBindingsCount++;
compileState->bindings.prepend(ref);
}
@@ -1892,10 +1931,14 @@ bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *p
Q_ASSERT(prop->value);
Q_ASSERT(prop->index != -1); // This is set in buildProperty()
+ compileState->objectDepth.push();
+
obj->addAttachedProperty(prop);
COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+ compileState->objectDepth.pop();
+
return true;
}
@@ -1953,7 +1996,11 @@ bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *pr
obj->addGroupedProperty(prop);
+ compileState->objectDepth.push();
+
COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+
+ compileState->objectDepth.pop();
}
return true;
@@ -1964,6 +2011,8 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
QDeclarativeScript::Object *baseObj,
const BindingContext &ctxt)
{
+ compileState->objectDepth.push();
+
if (obj->defaultProperty)
COMPILE_EXCEPTION(obj, tr("Invalid property use"));
obj->metatype = type->metaObject();
@@ -2026,6 +2075,8 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
obj->addValueProperty(prop);
}
+ compileState->objectDepth.pop();
+
return true;
}
@@ -2038,6 +2089,8 @@ bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
{
Q_ASSERT(prop->core.isQList());
+ compileState->listDepth.push();
+
int t = prop->type;
obj->addValueProperty(prop);
@@ -2071,6 +2124,8 @@ bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
}
}
+ compileState->listDepth.pop();
+
return true;
}
@@ -2408,7 +2463,6 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
QHashField methodNames;
// Check properties
- int dpCount = obj->dynamicProperties.count();
for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
const QDeclarativeScript::Object::DynamicProperty &prop = *p;
@@ -2983,7 +3037,7 @@ bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
// update the property type
type = aliasProperty.type();
- if (type >= QVariant::UserType)
+ if (type >= (int)QVariant::UserType)
type = 0;
}
@@ -3070,6 +3124,7 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi
((prop->index & 0xFF) << 24);
else
store.property = prop->index;
+ store.isRoot = (compileState->root == obj);
store.line = binding->location.start.line;
output->addInstruction(store);
} else if (ref.dataType == BindingReference::V8) {
@@ -3077,6 +3132,7 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi
store.value = ref.compiledIndex;
store.context = ref.bindingContext.stack;
store.owner = ref.bindingContext.owner;
+ store.isRoot = (compileState->root == obj);
store.line = binding->location.start.line;
Q_ASSERT(ref.bindingContext.owner == 0 ||
@@ -3093,6 +3149,7 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi
store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
store.assignBinding.context = ref.bindingContext.stack;
store.assignBinding.owner = ref.bindingContext.owner;
+ store.assignBinding.isRoot = (compileState->root == obj);
store.assignBinding.line = binding->location.start.line;
Q_ASSERT(ref.bindingContext.owner == 0 ||
@@ -3241,6 +3298,10 @@ bool QDeclarativeCompiler::completeComponentBuild()
if (bindingCompiler.isValid())
compileState->compiledBindingData = bindingCompiler.program();
+ // Check pop()'s matched push()'s
+ Q_ASSERT(compileState->objectDepth.depth() == 0);
+ Q_ASSERT(compileState->listDepth.depth() == 0);
+
saveComponentState();
return true;
@@ -3302,8 +3363,7 @@ void QDeclarativeCompiler::dumpStats()
*/
bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
{
- const QMetaObject *toMo =
- enginePrivate->rawMetaObjectForType(to);
+ const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
const QMetaObject *fromMo = from->metaObject();
while (fromMo) {
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index a4def99c48..993c733d40 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -76,12 +76,15 @@ class QDeclarativeComponent;
class QDeclarativeContext;
class QDeclarativeContextData;
-class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount, public QDeclarativeCleanup
+class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount,
+ public QDeclarativeCleanup
{
public:
QDeclarativeCompiledData(QDeclarativeEngine *engine);
virtual ~QDeclarativeCompiledData();
+ QDeclarativeEngine *engine;
+
QString name;
QUrl url;
QDeclarativeTypeNameCache *importCache;
@@ -96,7 +99,6 @@ public:
QDeclarativePropertyCache *typePropertyCache;
QDeclarativeCompiledData *component;
- QObject *createInstance(QDeclarativeContextData *, const QBitField &, QList<QDeclarativeError> *) const;
const QMetaObject *metaObject() const;
QDeclarativePropertyCache *propertyCache() const;
QDeclarativePropertyCache *createPropertyCache(QDeclarativeEngine *);
@@ -111,7 +113,6 @@ public:
QList<QString> primitives;
QList<QByteArray> datas;
QByteArray bytecode;
- QList<QJSValue *> cachedClosures;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
QList<QDeclarativeScriptData *> scripts;
@@ -138,16 +139,21 @@ public:
QDeclarativeInstruction *instruction(int index);
QDeclarativeInstruction::Type instructionType(const QDeclarativeInstruction *instr);
+ bool isInitialized() const { return hasEngine(); }
+ void initialize(QDeclarativeEngine *);
+
protected:
+ virtual void destroy(); // From QDeclarativeRefCount
virtual void clear(); // From QDeclarativeCleanup
private:
+ friend class QDeclarativeCompiler;
+
int addInstructionHelper(QDeclarativeInstruction::Type type, QDeclarativeInstruction &instr);
void dump(QDeclarativeInstruction *, int idx = -1);
QDeclarativeCompiledData(const QDeclarativeCompiledData &other);
QDeclarativeCompiledData &operator=(const QDeclarativeCompiledData &other);
QByteArray packData;
- friend class QDeclarativeCompiler;
int pack(const char *, size_t);
int indexForString(const QString &);
@@ -204,16 +210,35 @@ namespace QDeclarativeCompilerTypes {
}
};
+ struct DepthStack {
+ DepthStack() : _depth(0), _maxDepth(0) {}
+ DepthStack(const DepthStack &o) : _depth(o._depth), _maxDepth(o._maxDepth) {}
+ DepthStack &operator=(const DepthStack &o) { _depth = o._depth; _maxDepth = o._maxDepth; return *this; }
+
+ int depth() const { return _depth; }
+ int maxDepth() const { return _maxDepth; }
+
+ void push() { ++_depth; _maxDepth = qMax(_depth, _maxDepth); }
+ void pop() { --_depth; Q_ASSERT(_depth >= 0); Q_ASSERT(_maxDepth > _depth); }
+
+ void pushPop(int count) { _maxDepth = qMax(_depth + count, _maxDepth); }
+ private:
+ int _depth;
+ int _maxDepth;
+ };
+
// Contains all the incremental compiler state about a component. As
// a single QML file can have multiple components defined, there may be
// more than one of these for each compile
struct ComponentCompileState : public QDeclarativePool::Class
{
ComponentCompileState()
- : parserStatusCount(0), pushedProperties(0), nested(false), v8BindingProgramLine(-1), root(0) {}
+ : parserStatusCount(0), totalBindingsCount(0), pushedProperties(0), nested(false),
+ v8BindingProgramLine(-1), root(0) {}
IdList ids;
int parserStatusCount;
+ int totalBindingsCount;
int pushedProperties;
bool nested;
@@ -222,6 +247,9 @@ namespace QDeclarativeCompilerTypes {
int v8BindingProgramLine;
int v8BindingProgramIndex;
+ DepthStack objectDepth;
+ DepthStack listDepth;
+
typedef QDeclarativeCompilerTypes::BindingReference B;
typedef QFieldList<B, &B::nextReference> BindingReferenceList;
BindingReferenceList bindings;
@@ -386,7 +414,6 @@ private:
QDeclarativeScript::Object *unitRoot;
QDeclarativeTypeData *unit;
-
// Compiler component statistics. Only collected if QML_COMPILER_STATS=1
struct ComponentStat
{
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index d5a55fed24..50c64713d5 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -54,6 +54,8 @@
#include "private/qdeclarativescript_p.h"
#include "private/qdeclarativedebugtrace_p.h"
#include "private/qdeclarativeenginedebugservice_p.h"
+#include "qdeclarativeincubator.h"
+#include "private/qdeclarativeincubator_p.h"
#include "private/qv8engine_p.h"
#include "private/qv8include_p.h"
@@ -65,7 +67,45 @@
QT_BEGIN_NAMESPACE
-class QByteArray;
+class QDeclarativeComponentExtension : public QV8Engine::Deletable
+{
+public:
+ QDeclarativeComponentExtension(QV8Engine *);
+ virtual ~QDeclarativeComponentExtension();
+
+ v8::Persistent<v8::Function> incubationConstructor;
+ v8::Persistent<v8::Script> initialProperties;
+ v8::Persistent<v8::Function> forceIncubation;
+};
+static V8_DEFINE_EXTENSION(QDeclarativeComponentExtension, componentExtension);
+
+/*
+ Try to do what's necessary for a reasonable display of the type
+ name, but no more (just enough for the client to do more extensive cleanup).
+
+ Should only be called when debugging is enabled.
+*/
+static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
+{
+ static const QString qmlMarker(QLatin1String("_QML"));
+ static const QChar underscore(QLatin1Char('_'));
+ static const QChar asterisk(QLatin1Char('*'));
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
+ QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
+ if (!type) {
+ //### optimize further?
+ int marker = typeName.indexOf(qmlMarker);
+ if (marker != -1 && marker < typeName.count() - 1) {
+ if (typeName[marker + 1] == underscore) {
+ const QString className = typeName.left(marker) + asterisk;
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
+ if (type)
+ typeName = QLatin1String(type->qmlTypeName());
+ }
+ }
+ }
+ return typeName;
+}
/*!
\class QDeclarativeComponent
@@ -615,165 +655,6 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q
}
/*!
- \qmlmethod object Component::createObject(Item parent, object properties)
-
- Creates and returns an object instance of this component that will have
- the given \a parent and \a properties. The \a properties argument is optional.
- Returns null if object creation fails.
-
- The object will be created in the same context as the one in which the component
- was created. This function will always return null when called on components
- which were not created in QML.
-
- If you wish to create an object without setting a parent, specify \c null for
- the \a parent value. Note that if the returned object is to be displayed, you
- must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
- property, or else the object will not be visible.
-
- If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
- it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
- since setting the Item parent does not change object ownership; only the graphical parent is changed.
-
- As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
- map of initial property values for the created object. These values are applied before object
- creation is finalized. (This is more efficient than setting property values after object creation,
- particularly where large sets of property values are defined, and also allows property bindings
- to be set up before the object is created.)
-
- The \a properties argument is specified as a map of property-value items. For example, the code
- below creates an object with initial \c x and \c y values of 100 and 200, respectively:
-
- \js
- var component = Qt.createComponent("Button.qml");
- if (component.status == Component.Ready)
- component.createObject(parent, {"x": 100, "y": 100});
- \endjs
-
- Dynamically created instances can be deleted with the \c destroy() method.
- See \l {Dynamic Object Management in QML} for more information.
-*/
-
-/*!
- \internal
- A version of create which returns a scriptObject, for use in script.
- This function will only work on components created in QML.
-
- Sets graphics object parent because forgetting to do this is a frequent
- and serious problem.
-*/
-void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
-{
- Q_ASSERT(args);
-
- Q_D(QDeclarativeComponent);
-
- Q_ASSERT(d->engine);
-
- QObject *parent = args->Length()?QDeclarativeEnginePrivate::get(d->engine)->v8engine()->toQObject((*args)[0]):0;
-
- v8::Local<v8::Object> valuemap;
- if (args->Length() >= 2) {
- v8::Local<v8::Value> v = (*args)[1];
- if (!v->IsObject() || v->IsArray()) {
- qmlInfo(this) << tr("createObject: value is not an object");
- args->returnValue(v8::Null());
- return;
- }
- valuemap = v8::Local<v8::Object>::Cast(v);
- }
-
- QV8Engine *v8engine = QDeclarativeEnginePrivate::get(d->engine)->v8engine();
- QObject *retn = d->createObjectWithInitialProperties(args->qmlGlobal(), valuemap, parent);
- if (!retn)
- args->returnValue(v8::Null());
- else
- args->returnValue(v8engine->newQObject(retn));
-}
-
-QObject *QDeclarativeComponentPrivate::createObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *parentObject)
-{
- Q_Q(QDeclarativeComponent);
- Q_ASSERT(engine);
-
- QDeclarativeContext *ctxt = q->creationContext();
- if (!ctxt) ctxt = engine->rootContext();
-
- QObject *parent = parentObject;
-
- QObject *ret = q->beginCreate(ctxt);
- if (!ret) {
- q->completeCreate();
- return 0;
- }
-
- if (parent) {
- ret->setParent(parent);
-
- QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
-
- bool needParent = false;
-
- for (int ii = 0; ii < functions.count(); ++ii) {
- QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, parent);
- if (res == QDeclarativePrivate::Parented) {
- needParent = false;
- break;
- } else if (res == QDeclarativePrivate::IncompatibleParent) {
- needParent = true;
- }
- }
-
- if (needParent)
- qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
- }
-
- return completeCreateObjectWithInitialProperties(qmlGlobal, valuemap, ret);
-}
-
-QObject *QDeclarativeComponentPrivate::completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QV8Engine *v8engine = ep->v8engine();
- v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
- Q_ASSERT(ov->IsObject());
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
-
- if (!valuemap.IsEmpty()) {
-
-#define SET_ARGS_SOURCE \
- "(function(object, values) {"\
- "try {"\
- "for(var property in values) {"\
- "try {"\
- "var properties = property.split(\".\");"\
- "var o = object;"\
- "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
- "o = o[properties[ii]];"\
- "}"\
- "o[properties[properties.length - 1]] = values[property];"\
- "} catch(e) {}"\
- "}"\
- "} catch(e) {}"\
- "})"
-
- v8::Local<v8::Script> script = v8engine->qmlModeCompile(SET_ARGS_SOURCE);
- v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(qmlGlobal));
-
- // Try catch isn't needed as the function itself is loaded with try/catch
- v8::Handle<v8::Value> args[] = { object, valuemap };
- function->Call(v8engine->global(), 2, args);
- }
-
- completeCreate();
-
- QDeclarativeData *ddata = QDeclarativeData::get(toCreate);
- Q_ASSERT(ddata);
- ddata->setImplicitDestructible();
-
- return v8engine->toQObject(object);
-}
-
-/*!
Create an object instance from this component. Returns 0 if creation
failed. \a context specifies the context within which to create the object
instance.
@@ -799,7 +680,7 @@ QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
component.
Create an object instance from this component. Returns 0 if creation
- failed. \a context specifies the context within which to create the object
+ failed. \a publicContext specifies the context within which to create the object
instance.
When QDeclarativeComponent constructs an instance, it occurs in three steps:
@@ -816,20 +697,18 @@ QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
communicate information to an instantiated component, as it allows their
initial values to be configured before property bindings take effect.
*/
-QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
+QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *publicContext)
{
Q_D(QDeclarativeComponent);
- QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
- if (rv) {
- QDeclarativeData *ddata = QDeclarativeData::get(rv);
- Q_ASSERT(ddata);
- ddata->indestructible = true;
- }
- return rv;
+
+ Q_ASSERT(publicContext);
+ QDeclarativeContextData *context = QDeclarativeContextData::get(publicContext);
+
+ return d->beginCreate(context);
}
QObject *
-QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
+QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context)
{
Q_Q(QDeclarativeComponent);
if (!context) {
@@ -857,105 +736,61 @@ QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, cons
return 0;
}
- return begin(context, creationContext, cc, start, &state, 0, bindings);
-}
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-/*
- Try to do what's necessary for a reasonable display of the type
- name, but no more (just enough for the client to do more extensive cleanup).
+ bool isRoot = enginePriv->inProgressCreations == 0;
+ enginePriv->inProgressCreations++;
+ state.errors.clear();
+ state.completePending = true;
- Should only be called when debugging is enabled.
-*/
-static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
-{
- static const QString qmlMarker(QLatin1String("_QML"));
- static const QChar underscore(QLatin1Char('_'));
- static const QChar asterisk(QLatin1Char('*'));
- QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
- QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
- if (!type) {
- //### optimize further?
- int marker = typeName.indexOf(qmlMarker);
- if (marker != -1 && marker < typeName.count() - 1) {
- if (typeName[marker + 1] == underscore) {
- const QString className = typeName.left(marker) + asterisk;
- type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
- if (type)
- typeName = QLatin1String(type->qmlTypeName());
- }
- }
- }
- return typeName;
-}
-
-QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
- QDeclarativeContextData *componentCreationContext,
- QDeclarativeCompiledData *component, int start,
- ConstructionState *state, QList<QDeclarativeError> *errors,
- const QBitField &bindings)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
- bool isRoot = !enginePriv->inBeginCreate;
-
- Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
- Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
-
- if (isRoot)
+ if (isRoot)
QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
- QDeclarativeContextData *ctxt = new QDeclarativeContextData;
- ctxt->isInternal = true;
- ctxt->url = component->url;
- ctxt->imports = component->importCache;
-
- // Nested global imports
- if (componentCreationContext && start != -1) {
- ctxt->importedScripts = componentCreationContext->importedScripts;
- for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
- ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
+ enginePriv->referenceScarceResources();
+ state.vme.init(context, cc, start);
+ QObject *rv = state.vme.execute(&state.errors);
+ enginePriv->dereferenceScarceResources();
+
+ if (rv && creationContext && start != -1) {
+ // A component that is logically created within another component instance shares the same
+ // instances of script imports. For example:
+ //
+ // import QtQuick 1.0
+ // import "test.js" as Test
+ // ListView {
+ // model: Test.getModel()
+ // delegate: Component {
+ // Text { text: Test.getValue(index); }
+ // }
+ // }
+ //
+ // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
+ // the inner context. We have to create a fresh persistent handle for each to prevent
+ // double dispose. It is possible we could do this more efficiently using some form of
+ // referencing instead.
+ QDeclarativeContextData *objectContext = QDeclarativeData::get(rv, false)->outerContext;
+ objectContext->importedScripts = creationContext->importedScripts;
+ for (int ii = 0; ii < objectContext->importedScripts.count(); ++ii)
+ objectContext->importedScripts[ii] = qPersistentNew<v8::Object>(objectContext->importedScripts[ii]);
}
- component->importCache->addref();
- ctxt->setParent(parentContext);
-
- enginePriv->inBeginCreate = true;
-
- QDeclarativeVME vme;
- enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QObject *rv = vme.run(ctxt, component, start, bindings);
- enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
-
- if (vme.isError()) {
- if(errors) *errors = vme.errors();
- else state->errors = vme.errors();
- }
-
- if (isRoot) {
- enginePriv->inBeginCreate = false;
-
- state->bindValues = enginePriv->bindValues;
- state->parserStatus = enginePriv->parserStatus;
- state->finalizedParserStatus = enginePriv->finalizedParserStatus;
- state->componentAttached = enginePriv->componentAttached;
- if (state->componentAttached)
- state->componentAttached->prev = &state->componentAttached;
-
- enginePriv->componentAttached = 0;
- enginePriv->bindValues.clear();
- enginePriv->parserStatus.clear();
- enginePriv->finalizedParserStatus.clear();
- state->completePending = true;
- enginePriv->inProgressCreations++;
+ if (rv) {
+ QDeclarativeData *ddata = QDeclarativeData::get(rv);
+ Q_ASSERT(ddata);
+ ddata->indestructible = true;
}
if (enginePriv->isDebugging && rv) {
- if (!parentContext->isInternal)
- parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
- QDeclarativeEngineDebugService::instance()->objectCreated(parentContext->engine, rv);
+ if (!context->isInternal)
+ context->asQDeclarativeContextPrivate()->instances.append(rv);
+ QDeclarativeEngineDebugService::instance()->objectCreated(engine, rv);
if (isRoot) {
- QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating,
+ buildTypeNameForDebug(rv->metaObject()));
QDeclarativeData *data = QDeclarativeData::get(rv);
- QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
+ Q_ASSERT(data);
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating,
+ cc->url, data->lineNumber);
}
}
@@ -965,106 +800,23 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
QObject *object, ConstructionState *state)
{
- bool isRoot = !enginePriv->inBeginCreate;
- enginePriv->inBeginCreate = true;
-
- QDeclarativeVME vme;
- vme.runDeferred(object);
-
- if (vme.isError())
- state->errors = vme.errors();
-
- if (isRoot) {
- enginePriv->inBeginCreate = false;
-
- state->bindValues = enginePriv->bindValues;
- state->parserStatus = enginePriv->parserStatus;
- state->finalizedParserStatus = enginePriv->finalizedParserStatus;
- state->componentAttached = enginePriv->componentAttached;
- if (state->componentAttached)
- state->componentAttached->prev = &state->componentAttached;
-
- enginePriv->componentAttached = 0;
- enginePriv->bindValues.clear();
- enginePriv->parserStatus.clear();
- enginePriv->finalizedParserStatus.clear();
- state->completePending = true;
- enginePriv->inProgressCreations++;
- }
+ enginePriv->inProgressCreations++;
+ state->errors.clear();
+ state->completePending = true;
+
+ state->vme.initDeferred(object);
+ state->vme.execute(&state->errors);
}
void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
{
if (state->completePending) {
+ state->vme.complete();
- for (int ii = 0; ii < state->bindValues.count(); ++ii) {
- QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
- state->bindValues.at(ii);
- for (int jj = 0; jj < bv.count; ++jj) {
- if(bv.at(jj)) {
- bv.at(jj)->m_mePtr = 0;
- bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
- QDeclarativePropertyPrivate::DontRemoveBinding);
- }
- }
- QDeclarativeEnginePrivate::clear(bv);
- }
-
- for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
- QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
- state->parserStatus.at(ii);
-
- for (int jj = ps.count - 1; jj >= 0; --jj) {
- QDeclarativeParserStatus *status = ps.at(jj);
- if (status && status->d) {
- status->d = 0;
- status->componentComplete();
- }
- }
- QDeclarativeEnginePrivate::clear(ps);
- }
-
- for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
- QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
- QObject *obj = status.first;
- if (obj) {
- void *args[] = { 0 };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
- status.second, args);
- }
- }
-
- //componentComplete() can register additional finalization objects
- //that are then never handled. Handle them manually here.
- if (1 == enginePriv->inProgressCreations) {
- for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) {
- QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii);
- QObject *obj = status.first;
- if (obj) {
- void *args[] = { 0 };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
- status.second, args);
- }
- }
- enginePriv->finalizedParserStatus.clear();
- }
-
- while (state->componentAttached) {
- QDeclarativeComponentAttached *a = state->componentAttached;
- a->rem();
- QDeclarativeData *d = QDeclarativeData::get(a->parent());
- Q_ASSERT(d);
- Q_ASSERT(d->context);
- a->add(&d->context->componentAttached);
- emit a->completed();
- }
-
- state->bindValues.clear();
- state->parserStatus.clear();
- state->finalizedParserStatus.clear();
state->completePending = false;
enginePriv->inProgressCreations--;
+
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
enginePriv->warning(enginePriv->erroredBindings->error);
@@ -1121,9 +873,9 @@ QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObj
if (!engine)
return a;
- if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
+ if (QDeclarativeEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- a->add(&p->componentAttached);
+ a->add(&p->activeVME->componentAttached);
} else {
QDeclarativeData *d = QDeclarativeData::get(obj);
Q_ASSERT(d);
@@ -1134,4 +886,427 @@ QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObj
return a;
}
+void QDeclarativeComponent::create(QDeclarativeIncubator &i, QDeclarativeContext *context,
+ QDeclarativeContext *forContext)
+{
+ Q_D(QDeclarativeComponent);
+
+ if (!context) {
+ qWarning("QDeclarativeComponent: Cannot create a component in a null context");
+ return;
+ }
+
+ QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
+ QDeclarativeContextData *forContextData = contextData;
+ if (forContext) forContextData = QDeclarativeContextData::get(forContext);
+
+ if (!contextData->isValid()) {
+ qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
+ return;
+ }
+
+ if (contextData->engine != d->engine) {
+ qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
+ return;
+ }
+
+ if (!isReady()) {
+ qWarning("QDeclarativeComponent: Component is not ready");
+ return;
+ }
+
+ i.clear();
+ QDeclarativeIncubatorPrivate *p = i.d;
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(d->engine);
+
+ p->component = d->cc; p->component->addref();
+ p->vme.init(contextData, d->cc, d->start);
+
+ enginePriv->incubate(i, forContextData);
+}
+
+class QV8IncubatorResource : public QV8ObjectResource,
+ public QDeclarativeIncubator
+{
+V8_RESOURCE_TYPE(IncubatorType)
+public:
+ QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
+
+ static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ForceIncubationGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ForceIncubation(const v8::Arguments &args);
+
+ static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info);
+
+ v8::Persistent<v8::Object> me;
+ QDeclarativeGuard<QObject> parent;
+ v8::Persistent<v8::Value> valuemap;
+ v8::Persistent<v8::Object> qmlGlobal;
+protected:
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+};
+
+static void QDeclarativeComponent_setQmlParent(QObject *me, QObject *parent)
+{
+ if (parent) {
+ me->setParent(parent);
+ typedef QDeclarativePrivate::AutoParentFunction APF;
+ QList<APF> functions = QDeclarativeMetaType::parentFunctions();
+
+ bool needParent = false;
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ QDeclarativePrivate::AutoParentResult res = functions.at(ii)(me, parent);
+ if (res == QDeclarativePrivate::Parented) {
+ needParent = false;
+ break;
+ } else if (res == QDeclarativePrivate::IncompatibleParent) {
+ needParent = true;
+ }
+ }
+ if (needParent)
+ qWarning("QDeclarativeComponent: Created graphical object was not "
+ "placed in the graphics scene.");
+ }
+}
+
+/*!
+ \qmlmethod object Component::createObject(Item parent, object properties)
+
+ Creates and returns an object instance of this component that will have
+ the given \a parent and \a properties. The \a properties argument is optional.
+ Returns null if object creation fails.
+
+ The object will be created in the same context as the one in which the component
+ was created. This function will always return null when called on components
+ which were not created in QML.
+
+ If you wish to create an object without setting a parent, specify \c null for
+ the \a parent value. Note that if the returned object is to be displayed, you
+ must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
+ property, or else the object will not be visible.
+
+ If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
+ it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
+ since setting the Item parent does not change object ownership; only the graphical parent is changed.
+
+ As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
+ map of initial property values for the created object. These values are applied before object
+ creation is finalized. (This is more efficient than setting property values after object creation,
+ particularly where large sets of property values are defined, and also allows property bindings
+ to be set up before the object is created.)
+
+ The \a properties argument is specified as a map of property-value items. For example, the code
+ below creates an object with initial \c x and \c y values of 100 and 200, respectively:
+
+ \js
+ var component = Qt.createComponent("Button.qml");
+ if (component.status == Component.Ready)
+ component.createObject(parent, {"x": 100, "y": 100});
+ \endjs
+
+ Dynamically created instances can be deleted with the \c destroy() method.
+ See \l {Dynamic Object Management in QML} for more information.
+*/
+void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
+{
+ Q_D(QDeclarativeComponent);
+ Q_ASSERT(d->engine);
+ Q_ASSERT(args);
+
+ QObject *parent = 0;
+ v8::Local<v8::Object> valuemap;
+
+ if (args->Length() >= 1)
+ parent = args->engine()->toQObject((*args)[0]);
+
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ args->returnValue(v8::Null());
+ return;
+ }
+ valuemap = v8::Local<v8::Object>::Cast(v);
+ }
+
+ QV8Engine *v8engine = args->engine();
+
+ QDeclarativeContext *ctxt = creationContext();
+ if (!ctxt) ctxt = d->engine->rootContext();
+
+ QObject *rv = beginCreate(ctxt);
+
+ if (!rv) {
+ args->returnValue(v8::Null());
+ return;
+ }
+
+ QDeclarativeComponent_setQmlParent(rv, parent);
+
+ v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+ QDeclarativeComponentExtension *e = componentExtension(v8engine);
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ }
+
+ d->completeCreate();
+
+ Q_ASSERT(QDeclarativeData::get(rv));
+ QDeclarativeData::get(rv)->setImplicitDestructible();
+
+ if (!rv)
+ args->returnValue(v8::Null());
+ else
+ args->returnValue(object);
+}
+
+void QDeclarativeComponent::incubateObject(QDeclarativeV8Function *args)
+{
+ Q_D(QDeclarativeComponent);
+ Q_ASSERT(d->engine);
+ Q_ASSERT(args);
+
+ QObject *parent = 0;
+ v8::Local<v8::Object> valuemap;
+ QDeclarativeIncubator::IncubationMode mode = QDeclarativeIncubator::Asynchronous;
+
+ if (args->Length() >= 1)
+ parent = args->engine()->toQObject((*args)[0]);
+
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ args->returnValue(v8::Null());
+ return;
+ }
+ valuemap = v8::Local<v8::Object>::Cast(v);
+ }
+
+ if (args->Length() >= 3) {
+ quint32 v = (*args)[2]->Uint32Value();
+ if (v == QDeclarativeIncubator::Asynchronous)
+ mode = QDeclarativeIncubator::Asynchronous;
+ else if (v == QDeclarativeIncubator::AsynchronousIfNested)
+ mode = QDeclarativeIncubator::AsynchronousIfNested;
+ else if (v == QDeclarativeIncubator::Synchronous)
+ mode = QDeclarativeIncubator::Synchronous;
+ }
+
+ QDeclarativeComponentExtension *e = componentExtension(args->engine());
+
+ QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
+ if (!valuemap.IsEmpty()) {
+ r->valuemap = qPersistentNew(valuemap);
+ r->qmlGlobal = qPersistentNew(args->qmlGlobal());
+ }
+ r->parent = parent;
+
+ create(*r, creationContext());
+
+ if (r->status() == QDeclarativeIncubator::Null) {
+ delete r;
+ args->returnValue(v8::Null());
+ } else {
+ v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
+ o->SetExternalResource(r);
+
+ if (r->status() == QDeclarativeIncubator::Loading)
+ r->me = qPersistentNew(o);
+
+ args->returnValue(o);
+ }
+}
+
+// XXX used by QSGLoader
+QObject *QDeclarativeComponentPrivate::completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QV8Engine *v8engine = ep->v8engine();
+ v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+ QDeclarativeComponentExtension *e = componentExtension(v8engine);
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ }
+
+ completeCreate();
+
+ QDeclarativeData *ddata = QDeclarativeData::get(toCreate);
+ Q_ASSERT(ddata);
+ ddata->setImplicitDestructible();
+
+ return v8engine->toQObject(object);
+}
+
+
+QDeclarativeComponentExtension::QDeclarativeComponentExtension(QV8Engine *engine)
+{
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ forceIncubation = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceIncubation, engine));
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetInternalFieldCount(1);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"),
+ QV8IncubatorResource::StatusChangedGetter,
+ QV8IncubatorResource::StatusChangedSetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
+ QV8IncubatorResource::StatusGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("object"),
+ QV8IncubatorResource::ObjectGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("forceIncubation"),
+ QV8IncubatorResource::ForceIncubationGetter);
+ incubationConstructor = qPersistentNew(ft->GetFunction());
+ }
+
+ {
+#define INITIALPROPERTIES_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for(var property in values) {"\
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+ initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
+#undef INITIALPROPERTIES_SOURCE
+ }
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return r->engine->newQObject(r->object());
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ForceIncubationGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return componentExtension(r->engine)->forceIncubation;
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ForceIncubation(const v8::Arguments &args)
+{
+ QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
+ if (!r)
+ V8THROW_TYPE("Not an incubator object");
+
+ r->forceIncubation();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return v8::Integer::NewFromUnsigned(r->status());
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ return info.This()->GetInternalField(0);
+}
+
+void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ info.This()->SetInternalField(0, value);
+}
+
+QDeclarativeComponentExtension::~QDeclarativeComponentExtension()
+{
+ qPersistentDispose(incubationConstructor);
+ qPersistentDispose(initialProperties);
+}
+
+QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
+: QV8ObjectResource(engine), QDeclarativeIncubator(m)
+{
+}
+
+void QV8IncubatorResource::setInitialState(QObject *o)
+{
+ QDeclarativeComponent_setQmlParent(o, parent);
+
+ if (!valuemap.IsEmpty()) {
+ QDeclarativeComponentExtension *e = componentExtension(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
+ v8::Handle<v8::Value> args[] = { me, valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
+
+ qPersistentDispose(valuemap);
+ qPersistentDispose(qmlGlobal);
+ }
+}
+
+void QV8IncubatorResource::statusChanged(Status s)
+{
+ if (s == Ready) {
+ Q_ASSERT(QDeclarativeData::get(object()));
+ QDeclarativeData::get(object())->setImplicitDestructible();
+ }
+
+ if (!me.IsEmpty()) { // Will be false in synchronous mode
+ v8::HandleScope scope;
+ v8::Local<v8::Value> callback = me->GetInternalField(0);
+
+ if (!callback.IsEmpty() && !callback->IsUndefined()) {
+
+ if (callback->IsFunction()) {
+ v8::Context::Scope context_scope(engine->context());
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+ v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
+ // XXX TryCatch
+ f->Call(me, 1, args);
+ }
+ }
+ }
+
+ if (s == Ready || s == Error) {
+ qPersistentDispose(valuemap);
+ qPersistentDispose(qmlGlobal);
+ // No further status changes are forthcoming, so we no long need a self reference
+ qPersistentDispose(me);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index a3457d1446..92af689358 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -55,12 +55,15 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
-class QDeclarativeCompiledData;
class QByteArray;
-class QDeclarativeComponentPrivate;
class QDeclarativeEngine;
-class QDeclarativeComponentAttached;
+class QDeclarativeComponent;
+class QDeclarativeIncubator;
class QDeclarativeV8Function;
+class QDeclarativeCompiledData;
+class QDeclarativeComponentPrivate;
+class QDeclarativeComponentAttached;
+
class Q_DECLARATIVE_EXPORT QDeclarativeComponent : public QObject
{
Q_OBJECT
@@ -97,6 +100,9 @@ public:
virtual QObject *beginCreate(QDeclarativeContext *);
virtual void completeCreate();
+ void create(QDeclarativeIncubator &, QDeclarativeContext *context,
+ QDeclarativeContext *forContext = 0);
+
QDeclarativeContext *creationContext() const;
static QDeclarativeComponentAttached *qmlAttachedProperties(QObject *);
@@ -112,6 +118,7 @@ Q_SIGNALS:
protected:
QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject* parent);
Q_INVOKABLE void createObject(QDeclarativeV8Function *);
+ Q_INVOKABLE void incubateObject(QDeclarativeV8Function *);
private:
QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, QObject *parent);
diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h
index ba937491b7..7e6f9c2d30 100644
--- a/src/declarative/qml/qdeclarativecomponent_p.h
+++ b/src/declarative/qml/qdeclarativecomponent_p.h
@@ -59,6 +59,7 @@
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativetypeloader_p.h"
#include "private/qbitfield_p.h"
+#include "private/qdeclarativevme_p.h"
#include "qdeclarativeerror.h"
#include "qdeclarative.h"
@@ -84,9 +85,8 @@ class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, pu
public:
QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0) {}
- QObject *beginCreate(QDeclarativeContextData *, const QBitField &);
+ QObject *beginCreate(QDeclarativeContextData *);
void completeCreate();
- QObject *createObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *parentObject);
QObject *completeCreateObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
QDeclarativeTypeData *typeData;
@@ -102,25 +102,18 @@ public:
QDeclarativeCompiledData *cc;
struct ConstructionState {
- ConstructionState() : componentAttached(0), completePending(false) {}
- QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> > bindValues;
- QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> > parserStatus;
- QList<QPair<QDeclarativeGuard<QObject>, int> > finalizedParserStatus;
- QDeclarativeComponentAttached *componentAttached;
+ ConstructionState() : completePending(false) {}
+
+ QDeclarativeVME vme;
QList<QDeclarativeError> errors;
bool completePending;
};
ConstructionState state;
- static QObject *begin(QDeclarativeContextData *parentContext, QDeclarativeContextData *componentCreationContext,
- QDeclarativeCompiledData *component, int start,
- ConstructionState *state, QList<QDeclarativeError> *errors,
- const QBitField &bindings = QBitField());
static void beginDeferred(QDeclarativeEnginePrivate *enginePriv, QObject *object,
ConstructionState *state);
static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state);
-
QDeclarativeEngine *engine;
QDeclarativeGuardedContextData creationContext;
@@ -155,8 +148,8 @@ Q_SIGNALS:
void destruction();
private:
+ friend class QDeclarativeVME;
friend class QDeclarativeContextData;
- friend class QDeclarativeComponentPrivate;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index ff6e628c66..73f05e47b2 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -510,17 +510,19 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false),
- publicContext(0), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
- expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0), v4bindings(0), v8bindings(0)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
+ isPragmaLibraryContext(false), publicContext(0), activeVME(0), propertyNames(0), contextObject(0),
+ imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
+ contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0),
+ v4bindings(0), v8bindings(0)
{
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false),
- publicContext(ctxt), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
- expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
+ isPragmaLibraryContext(false), publicContext(ctxt), activeVME(0), propertyNames(0),
+ contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0),
+ contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0), v4bindings(0), v8bindings(0)
{
}
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index 9a068bbf8d..05750b06f5 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -108,6 +108,7 @@ public:
static QObject *context_at(QDeclarativeListProperty<QObject> *, int);
};
+class QDeclarativeVME;
class QDeclarativeComponentAttached;
class QDeclarativeGuardedContextData;
class Q_DECLARATIVE_EXPORT QDeclarativeContextData
@@ -145,6 +146,10 @@ public:
quint32 dummy:28;
QDeclarativeContext *publicContext;
+ // VME that is constructing this context if any
+ // XXX remove if possible
+ QDeclarativeVME *activeVME;
+
// Property name cache
QDeclarativeIntegerCache *propertyNames;
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index f55c290aa0..4c8d48f6ef 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -68,6 +68,7 @@
#include "private/qdeclarativedebugtrace_p.h"
#include "private/qdeclarativeapplication_p.h"
#include "private/qv8debugservice_p.h"
+#include "qdeclarativeincubator.h"
#include <QtCore/qmetaobject.h>
#include <QNetworkReply>
@@ -90,6 +91,7 @@
#include <QtCore/qmutex.h>
#include <QtGui/qcolor.h>
#include <QtCore/qcryptographichash.h>
+#include <QtNetwork/qnetworkconfigmanager.h>
#include <private/qobject_p.h>
@@ -340,10 +342,10 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
: captureProperties(false), rootContext(0), isDebugging(false),
outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
cleanup(0), erroredBindings(0), inProgressCreations(0),
- workerScriptEngine(0), componentAttached(0), inBeginCreate(false),
+ workerScriptEngine(0), activeVME(0),
networkAccessManager(0), networkAccessManagerFactory(0),
scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
- sgContext(0)
+ incubatorCount(0), incubationController(0), sgContext(0), mutex(QMutex::Recursive)
{
if (!qt_QmlQtModule_registered) {
qt_QmlQtModule_registered = true;
@@ -358,8 +360,6 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
{
Q_ASSERT(inProgressCreations == 0);
- Q_ASSERT(bindValues.isEmpty());
- Q_ASSERT(parserStatus.isEmpty());
while (cleanup) {
QDeclarativeCleanup *c = cleanup;
@@ -370,6 +370,11 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
c->clear();
}
+ doDeleteInEngineThread();
+
+ if (incubationController) incubationController->d = 0;
+ incubationController = 0;
+
delete rootContext;
rootContext = 0;
@@ -385,21 +390,6 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
}
}
-void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs)
-{
- bvs.clear();
-}
-
-void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeParserStatus> &pss)
-{
- for (int ii = 0; ii < pss.count; ++ii) {
- QDeclarativeParserStatus *ps = pss.at(ii);
- if(ps)
- ps->d = 0;
- }
- pss.clear();
-}
-
void QDeclarativePrivate::qdeclarativeelement_destructor(QObject *o)
{
QObjectPrivate *p = QObjectPrivate::get(o);
@@ -430,6 +420,18 @@ void QDeclarativeData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o
void QDeclarativeEnginePrivate::init()
{
Q_Q(QDeclarativeEngine);
+
+ static bool firstTime = true;
+ if (firstTime) {
+ // This is a nasty hack as QNetworkAccessManager will issue a
+ // BlockingQueuedConnection to the main thread if it is initialized for the
+ // first time on a non-main thread. This can cause a lockup if the main thread
+ // is blocking on the thread that initialize the network access manager.
+ QNetworkConfigurationManager man;
+
+ firstTime = false;
+ }
+
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<QDeclarativeScriptString>("QDeclarativeScriptString");
qRegisterMetaType<QJSValue>("QJSValue");
@@ -597,6 +599,16 @@ QDeclarativeNetworkAccessManagerFactory *QDeclarativeEngine::networkAccessManage
return d->networkAccessManagerFactory;
}
+void QDeclarativeEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
+{
+ if (activeVME) {
+ activeVME->finalizeCallbacks.append(qMakePair(QDeclarativeGuard<QObject>(obj), index));
+ } else {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
+ }
+}
+
QNetworkAccessManager *QDeclarativeEnginePrivate::createNetworkAccessManager(QObject *parent) const
{
QMutexLocker locker(&mutex);
@@ -912,6 +924,26 @@ QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject
return ddata->indestructible?CppOwnership:JavaScriptOwnership;
}
+bool QDeclarativeEngine::event(QEvent *e)
+{
+ Q_D(QDeclarativeEngine);
+ if (e->type() == QEvent::User)
+ d->doDeleteInEngineThread();
+
+ return QJSEngine::event(e);
+}
+
+void QDeclarativeEnginePrivate::doDeleteInEngineThread()
+{
+ QFieldList<Deletable, &Deletable::next> list;
+ mutex.lock();
+ list.copyAndClear(toDeleteInEngineThread);
+ mutex.unlock();
+
+ while (Deletable *d = list.takeFirst())
+ delete d;
+}
+
Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
{
QDeclarativeData *data = QDeclarativeData::get(object);
@@ -1468,6 +1500,7 @@ QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeTy
int maxMinorVersion = 0;
const QMetaObject *metaObject = type->metaObject();
+
while (metaObject) {
QDeclarativeType *t = QDeclarativeMetaType::qmlType(metaObject, type->module(),
type->majorVersion(), minorVersion);
@@ -1562,44 +1595,31 @@ QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeTy
return raw;
}
-void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData *data)
+QDeclarativeMetaType::ModuleApiInstance *
+QDeclarativeEnginePrivate::moduleApiInstance(const QDeclarativeMetaType::ModuleApi &module)
{
- QByteArray name = data->root->className();
-
- QByteArray ptr = name + '*';
- QByteArray lst = "QDeclarativeListProperty<" + name + '>';
+ Locker locker(this);
- int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor,
- voidptr_constructor);
- int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor,
- voidptr_constructor);
-
- m_qmlLists.insert(lst_type, ptr_type);
- m_compositeTypes.insert(ptr_type, data);
- data->addref();
-}
-
-bool QDeclarativeEnginePrivate::isList(int t) const
-{
- return m_qmlLists.contains(t) || QDeclarativeMetaType::isList(t);
-}
+ QDeclarativeMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
+ if (!a) {
+ a = new QDeclarativeMetaType::ModuleApiInstance;
+ a->scriptCallback = module.script;
+ a->qobjectCallback = module.qobject;
+ moduleApiInstances.insert(module, a);
+ }
-int QDeclarativeEnginePrivate::listType(int t) const
-{
- QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
- if (iter != m_qmlLists.end())
- return *iter;
- else
- return QDeclarativeMetaType::listType(t);
+ return a;
}
bool QDeclarativeEnginePrivate::isQObject(int t)
{
+ Locker locker(this);
return m_compositeTypes.contains(t) || QDeclarativeMetaType::isQObject(t);
}
QObject *QDeclarativeEnginePrivate::toQObject(const QVariant &v, bool *ok) const
{
+ Locker locker(this);
int t = v.userType();
if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
if (ok) *ok = true;
@@ -1611,6 +1631,7 @@ QObject *QDeclarativeEnginePrivate::toQObject(const QVariant &v, bool *ok) const
QDeclarativeMetaType::TypeCategory QDeclarativeEnginePrivate::typeCategory(int t) const
{
+ Locker locker(this);
if (m_compositeTypes.contains(t))
return QDeclarativeMetaType::Object;
else if (m_qmlLists.contains(t))
@@ -1619,8 +1640,25 @@ QDeclarativeMetaType::TypeCategory QDeclarativeEnginePrivate::typeCategory(int t
return QDeclarativeMetaType::typeCategory(t);
}
+bool QDeclarativeEnginePrivate::isList(int t) const
+{
+ Locker locker(this);
+ return m_qmlLists.contains(t) || QDeclarativeMetaType::isList(t);
+}
+
+int QDeclarativeEnginePrivate::listType(int t) const
+{
+ Locker locker(this);
+ QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
+ if (iter != m_qmlLists.end())
+ return *iter;
+ else
+ return QDeclarativeMetaType::listType(t);
+}
+
const QMetaObject *QDeclarativeEnginePrivate::rawMetaObjectForType(int t) const
{
+ Locker locker(this);
QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
if (iter != m_compositeTypes.end()) {
return (*iter)->root;
@@ -1632,6 +1670,7 @@ const QMetaObject *QDeclarativeEnginePrivate::rawMetaObjectForType(int t) const
const QMetaObject *QDeclarativeEnginePrivate::metaObjectForType(int t) const
{
+ Locker locker(this);
QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
if (iter != m_compositeTypes.end()) {
return (*iter)->root;
@@ -1641,6 +1680,25 @@ const QMetaObject *QDeclarativeEnginePrivate::metaObjectForType(int t) const
}
}
+void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData *data)
+{
+ QByteArray name = data->root->className();
+
+ QByteArray ptr = name + '*';
+ QByteArray lst = "QDeclarativeListProperty<" + name + '>';
+
+ int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor,
+ voidptr_constructor);
+ int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor,
+ voidptr_constructor);
+
+ data->addref();
+
+ Locker locker(this);
+ m_qmlLists.insert(lst_type, ptr_type);
+ m_compositeTypes.insert(ptr_type, data);
+}
+
bool QDeclarative_isFileCaseCorrect(const QString &fileName)
{
#if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
index 25b254feaa..4d5aa34a36 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -66,6 +66,7 @@ class QScriptContext;
class QDeclarativeImageProvider;
class QNetworkAccessManager;
class QDeclarativeNetworkAccessManagerFactory;
+class QDeclarativeIncubationController;
class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QJSEngine
{
Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
@@ -98,6 +99,9 @@ public:
QDeclarativeImageProvider *imageProvider(const QString &id) const;
void removeImageProvider(const QString &id);
+ void setIncubationController(QDeclarativeIncubationController *);
+ QDeclarativeIncubationController *incubationController() const;
+
void setOfflineStoragePath(const QString& dir);
QString offlineStoragePath() const;
@@ -116,6 +120,9 @@ public:
static void setObjectOwnership(QObject *, ObjectOwnership);
static ObjectOwnership objectOwnership(QObject *);
+protected:
+ virtual bool event(QEvent *);
+
Q_SIGNALS:
void quit();
void warnings(const QList<QDeclarativeError> &warnings);
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index be4f714545..03d56e2804 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -70,11 +70,12 @@
#include "private/qdeclarativedirparser_p.h"
#include "private/qintrusivelist_p.h"
-#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qstack.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qthread.h>
#include <private/qobject_p.h>
@@ -87,7 +88,6 @@ class QDeclarativeEngine;
class QDeclarativeContextPrivate;
class QDeclarativeExpression;
class QDeclarativeImportDatabase;
-class ScarceResourceData;
class QNetworkReply;
class QNetworkAccessManager;
class QDeclarativeNetworkAccessManagerFactory;
@@ -97,8 +97,10 @@ class QDeclarativeComponentAttached;
class QDeclarativeCleanup;
class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
+class QDeclarativeVME;
class QDir;
class QSGTexture;
+class QDeclarativeIncubator;
class QSGContext;
class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate
@@ -146,42 +148,10 @@ public:
QUrl baseUrl;
- template<class T>
- struct SimpleList {
- SimpleList()
- : count(0), values(0) {}
- SimpleList(int r)
- : count(0), values(new T*[r]) {}
-
- int count;
- T **values;
-
- void append(T *v) {
- values[count++] = v;
- }
-
- T *at(int idx) const {
- return values[idx];
- }
-
- void clear() {
- delete [] values;
- }
- };
-
- static void clear(SimpleList<QDeclarativeAbstractBinding> &);
- static void clear(SimpleList<QDeclarativeParserStatus> &);
-
- QList<SimpleList<QDeclarativeAbstractBinding> > bindValues;
- QList<SimpleList<QDeclarativeParserStatus> > parserStatus;
- QList<QPair<QDeclarativeGuard<QObject>,int> > finalizedParserStatus;
- QDeclarativeComponentAttached *componentAttached;
+ typedef QPair<QDeclarativeGuard<QObject>,int> FinalizeCallback;
+ void registerFinalizeCallback(QObject *obj, int index);
- void registerFinalizedParserStatusObject(QObject *obj, int index) {
- finalizedParserStatus.append(qMakePair(QDeclarativeGuard<QObject>(obj), index));
- }
-
- bool inBeginCreate;
+ QDeclarativeVME *activeVME;
QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
@@ -211,32 +181,43 @@ public:
void referenceScarceResources();
void dereferenceScarceResources();
- mutable QMutex mutex;
-
QDeclarativeTypeLoader typeLoader;
QDeclarativeImportDatabase importDatabase;
QString offlineStoragePath;
mutable quint32 uniqueId;
- quint32 getUniqueId() const {
+ inline quint32 getUniqueId() const {
return uniqueId++;
}
QDeclarativeValueTypeFactory valueTypes;
- QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
-
- QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
- QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
+ // Unfortunate workaround to avoid a circular dependency between
+ // qdeclarativeengine_p.h and qdeclarativeincubator_p.h
+ struct Incubator { QIntrusiveListNode next; };
+ QIntrusiveList<Incubator, &Incubator::next> incubatorList;
+ unsigned int incubatorCount;
+ QDeclarativeIncubationController *incubationController;
+ void incubate(QDeclarativeIncubator &, QDeclarativeContextData *);
+
+ // These methods may be called from any thread
+ inline bool isEngineThread() const;
+ inline static bool isEngineThread(const QDeclarativeEngine *);
+ template<typename T>
+ inline void deleteInEngineThread(T *);
+ template<typename T>
+ inline static void deleteInEngineThread(QDeclarativeEngine *, T *);
+
+ // These methods may be called from the loader thread
+ QDeclarativeMetaType::ModuleApiInstance *moduleApiInstance(const QDeclarativeMetaType::ModuleApi &module);
+
+ // These methods may be called from the loader thread
inline QDeclarativePropertyCache *cache(QObject *obj);
inline QDeclarativePropertyCache *cache(const QMetaObject *);
inline QDeclarativePropertyCache *cache(QDeclarativeType *, int, QDeclarativeError &error);
- QDeclarativePropertyCache *createCache(const QMetaObject *);
- QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error);
-
- void registerCompositeType(QDeclarativeCompiledData *);
+ // These methods may be called from the loader thread
bool isQObject(int);
QObject *toQObject(const QVariant &, bool *ok = 0) const;
QDeclarativeMetaType::TypeCategory typeCategory(int) const;
@@ -244,8 +225,7 @@ public:
int listType(int) const;
const QMetaObject *rawMetaObjectForType(int) const;
const QMetaObject *metaObjectForType(int) const;
- QHash<int, int> m_qmlLists;
- QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
+ void registerCompositeType(QDeclarativeCompiledData *);
void sendQuit();
void warning(const QDeclarativeError &);
@@ -255,11 +235,12 @@ public:
static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
- static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return e->d_func()->v8engine(); }
- static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); }
- static QDeclarativeEnginePrivate *get(QDeclarativeContext *c) { return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0; }
- static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; }
- static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); }
+ inline static QV8Engine *getV8Engine(QDeclarativeEngine *e);
+ inline static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e);
+ inline static const QDeclarativeEnginePrivate *get(const QDeclarativeEngine *e);
+ inline static QDeclarativeEnginePrivate *get(QDeclarativeContext *c);
+ inline static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c);
+ inline static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p);
static QString urlToLocalFileOrQrc(const QUrl& url);
static QString urlToLocalFileOrQrc(const QString& url);
@@ -270,8 +251,149 @@ public:
static bool qml_debugging_enabled;
QSGContext *sgContext;
+
+ mutable QMutex mutex;
+
+private:
+ // Locker locks the QDeclarativeEnginePrivate data structures for read and write, if necessary.
+ // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
+ // either idle, or is running with the main thread blocked, no locking is necessary. This way
+ // we only pay for locking when we have to.
+ // Consequently, this class should only be used to protect simple accesses or modifications of the
+ // QDeclarativeEnginePrivate structures or operations that can be guarenteed not to start activity
+ // on the loader thread.
+ // The Locker API is identical to QMutexLocker. Locker reuses the QDeclarativeEnginePrivate::mutex
+ // QMutex instance and multiple Lockers are recursive in the same thread.
+ class Locker
+ {
+ public:
+ inline Locker(const QDeclarativeEngine *);
+ inline Locker(const QDeclarativeEnginePrivate *);
+ inline ~Locker();
+
+ inline void unlock();
+ inline void relock();
+
+ private:
+ const QDeclarativeEnginePrivate *m_ep;
+ quint32 m_locked:1;
+ };
+
+ // Must be called locked
+ QDeclarativePropertyCache *createCache(const QMetaObject *);
+ QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error);
+
+ // These members must be protected by a QDeclarativeEnginePrivate::Locker as they are required by
+ // the threaded loader. Only access them through their respective accessor methods.
+ QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
+ QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
+ QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
+ QHash<int, int> m_qmlLists;
+ QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
+
+ // These members is protected by the full QDeclarativeEnginePrivate::mutex mutex
+ struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
+ QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
+ void doDeleteInEngineThread();
};
+QDeclarativeEnginePrivate::Locker::Locker(const QDeclarativeEngine *e)
+: m_ep(QDeclarativeEnginePrivate::get(e))
+{
+ relock();
+}
+
+QDeclarativeEnginePrivate::Locker::Locker(const QDeclarativeEnginePrivate *e)
+: m_ep(e), m_locked(false)
+{
+ relock();
+}
+
+QDeclarativeEnginePrivate::Locker::~Locker()
+{
+ unlock();
+}
+
+void QDeclarativeEnginePrivate::Locker::unlock()
+{
+ if (m_locked) {
+ m_ep->mutex.unlock();
+ m_locked = false;
+ }
+}
+
+void QDeclarativeEnginePrivate::Locker::relock()
+{
+ Q_ASSERT(!m_locked);
+ if (m_ep->typeLoader.isConcurrent()) {
+ m_ep->mutex.lock();
+ m_locked = true;
+ }
+}
+
+/*!
+Returns true if the calling thread is the QDeclarativeEngine thread.
+*/
+bool QDeclarativeEnginePrivate::isEngineThread() const
+{
+ Q_Q(const QDeclarativeEngine);
+ return QThread::currentThread() == q->thread();
+}
+
+/*!
+Returns true if the calling thread is the QDeclarativeEngine \a engine thread.
+*/
+bool QDeclarativeEnginePrivate::isEngineThread(const QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ return QDeclarativeEnginePrivate::get(engine)->isEngineThread();
+}
+
+/*!
+Delete \a value in the engine thread. If the calling thread is the engine
+thread, \a value will be deleted immediately.
+
+This method should be used for *any* type that has resources that need to
+be freed in the engine thread. This is generally types that use V8 handles.
+As there is some small overhead in checking the current thread, it is best
+practice to check if any V8 handles actually need to be freed and delete
+the instance directly if not.
+*/
+template<typename T>
+void QDeclarativeEnginePrivate::deleteInEngineThread(T *value)
+{
+ Q_Q(QDeclarativeEngine);
+
+ Q_ASSERT(value);
+ if (isEngineThread()) {
+ delete value;
+ } else {
+ struct I : public Deletable {
+ I(T *value) : value(value) {}
+ ~I() { delete value; }
+ T *value;
+ };
+ I *i = new I(value);
+ mutex.lock();
+ bool wasEmpty = toDeleteInEngineThread.isEmpty();
+ toDeleteInEngineThread.append(i);
+ mutex.unlock();
+ if (wasEmpty)
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ }
+}
+
+/*!
+Delete \a value in the \a engine thread. If the calling thread is the engine
+thread, \a value will be deleted immediately.
+*/
+template<typename T>
+void QDeclarativeEnginePrivate::deleteInEngineThread(QDeclarativeEngine *engine, T *value)
+{
+ Q_ASSERT(engine);
+ QDeclarativeEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
+}
+
/*!
Returns a QDeclarativePropertyCache for \a obj if one is available.
@@ -279,12 +401,20 @@ If \a obj is null, being deleted or contains a dynamic meta object 0
is returned.
The returned cache is not referenced, so if it is to be stored, call addref().
+
+XXX thread There is a potential future race condition in this and all the cache()
+functions. As the QDeclarativePropertyCache is returned unreferenced, when called
+from the loader thread, it is possible that the cache will have been dereferenced
+and deleted before the loader thread has a chance to use or reference it. This
+can't currently happen as the cache holds a reference to the
+QDeclarativePropertyCache until the QDeclarativeEngine is destroyed.
*/
QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QObject *obj)
{
if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
return 0;
+ Locker locker(this);
const QMetaObject *mo = obj->metaObject();
QDeclarativePropertyCache *rv = propertyCache.value(mo);
if (!rv) rv = createCache(mo);
@@ -304,6 +434,7 @@ QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(const QMetaObject *m
{
Q_ASSERT(metaObject);
+ Locker locker(this);
QDeclarativePropertyCache *rv = propertyCache.value(metaObject);
if (!rv) rv = createCache(metaObject);
return rv;
@@ -321,11 +452,42 @@ QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QDeclarativeType *ty
if (minorVersion == -1 || !type->containsRevisionedAttributes())
return cache(type->metaObject());
+ Locker locker(this);
QDeclarativePropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
if (!rv) rv = createCache(type, minorVersion, error);
return rv;
}
+QV8Engine *QDeclarativeEnginePrivate::getV8Engine(QDeclarativeEngine *e)
+{
+ return e->d_func()->v8engine();
+}
+
+QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeEngine *e)
+{
+ return e->d_func();
+}
+
+const QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(const QDeclarativeEngine *e)
+{
+ return e->d_func();
+}
+
+QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeContext *c)
+{
+ return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0;
+}
+
+QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeContextData *c)
+{
+ return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0;
+}
+
+QDeclarativeEngine *QDeclarativeEnginePrivate::get(QDeclarativeEnginePrivate *p)
+{
+ return p->q_func();
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEENGINE_P_H
diff --git a/src/declarative/qml/qdeclarativeextensioninterface.h b/src/declarative/qml/qdeclarativeextensioninterface.h
index 29e856bf49..3d2b3c6c7e 100644
--- a/src/declarative/qml/qdeclarativeextensioninterface.h
+++ b/src/declarative/qml/qdeclarativeextensioninterface.h
@@ -52,13 +52,19 @@ QT_MODULE(Declarative)
class QDeclarativeEngine;
-struct Q_DECLARATIVE_EXPORT QDeclarativeExtensionInterface
+struct Q_DECLARATIVE_EXPORT QDeclarativeTypesExtensionInterface
{
- virtual ~QDeclarativeExtensionInterface() {}
+ virtual ~QDeclarativeTypesExtensionInterface() {}
virtual void registerTypes(const char *uri) = 0;
+};
+
+struct Q_DECLARATIVE_EXPORT QDeclarativeExtensionInterface : public QDeclarativeTypesExtensionInterface
+{
+ virtual ~QDeclarativeExtensionInterface() {}
virtual void initializeEngine(QDeclarativeEngine *engine, const char *uri) = 0;
};
+Q_DECLARE_INTERFACE(QDeclarativeTypesExtensionInterface, "com.trolltech.Qt.QDeclarativeTypesExtensionInterface/1.0")
Q_DECLARE_INTERFACE(QDeclarativeExtensionInterface, "com.trolltech.Qt.QDeclarativeExtensionInterface/1.0")
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeextensionplugin.h b/src/declarative/qml/qdeclarativeextensionplugin.h
index a249fba9b9..fbc609990a 100644
--- a/src/declarative/qml/qdeclarativeextensionplugin.h
+++ b/src/declarative/qml/qdeclarativeextensionplugin.h
@@ -54,10 +54,12 @@ QT_MODULE(Declarative)
class QDeclarativeEngine;
-class Q_DECLARATIVE_EXPORT QDeclarativeExtensionPlugin : public QObject, public QDeclarativeExtensionInterface
+class Q_DECLARATIVE_EXPORT QDeclarativeExtensionPlugin : public QObject,
+ public QDeclarativeExtensionInterface
{
Q_OBJECT
Q_INTERFACES(QDeclarativeExtensionInterface)
+ Q_INTERFACES(QDeclarativeTypesExtensionInterface)
public:
explicit QDeclarativeExtensionPlugin(QObject *parent = 0);
~QDeclarativeExtensionPlugin();
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp
index 64bdaf108a..21e91de910 100644
--- a/src/declarative/qml/qdeclarativeimport.cpp
+++ b/src/declarative/qml/qdeclarativeimport.cpp
@@ -213,19 +213,10 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(data.uri, data.majversion, data.minversion);
if (moduleApi.script || moduleApi.qobject) {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeMetaType::ModuleApiInstance *a = ep->moduleApiInstances.value(moduleApi);
- if (!a) {
- a = new QDeclarativeMetaType::ModuleApiInstance;
- a->scriptCallback = moduleApi.script;
- a->qobjectCallback = moduleApi.qobject;
- ep->moduleApiInstances.insert(moduleApi, a);
- }
- import.moduleApi = a;
+ import.moduleApi = ep->moduleApiInstance(moduleApi);
}
}
}
-
-
}
/*!
@@ -1092,22 +1083,29 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
return false;
}
- if (QDeclarativeExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(loader.instance())) {
+ QObject *instance = loader.instance();
+ if (QDeclarativeTypesExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(instance)) {
const QByteArray bytes = uri.toUtf8();
const char *moduleId = bytes.constData();
if (!typesRegistered) {
- // ### this code should probably be protected with a mutex.
+ // XXX thread this code should probably be protected with a mutex.
qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
iface->registerTypes(moduleId);
}
if (!engineInitialized) {
- // things on the engine (eg. adding new global objects) have to be done for every engine.
-
- // protect against double initialization
+ // things on the engine (eg. adding new global objects) have to be done for every
+ // engine.
+ // XXX protect against double initialization
initializedPlugins.insert(absoluteFilePath);
- iface->initializeEngine(engine, moduleId);
+
+ QDeclarativeExtensionInterface *eiface =
+ qobject_cast<QDeclarativeExtensionInterface *>(instance);
+ if (eiface) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ ep->typeLoader.initializeEngine(eiface, moduleId);
+ }
}
} else {
if (errors) {
diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h
index 7f0b499881..7da4aa5ca1 100644
--- a/src/declarative/qml/qdeclarativeimport_p.h
+++ b/src/declarative/qml/qdeclarativeimport_p.h
@@ -134,6 +134,7 @@ private:
const QString &baseName);
+ // XXX thread
QStringList filePluginPath;
QStringList fileImportPath;
diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp
new file mode 100644
index 0000000000..e10575f0ae
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeincubator.cpp
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeincubator.h"
+#include "qdeclarativeincubator_p.h"
+
+#include <private/qdeclarativecompiler_p.h>
+#include <private/qdeclarativeexpression_p.h>
+
+// XXX TODO
+// - check that the Component.onCompleted behavior is the same as 4.8 in the synchronous and
+// async if nested cases
+void QDeclarativeEnginePrivate::incubate(QDeclarativeIncubator &i, QDeclarativeContextData *forContext)
+{
+ QDeclarativeIncubatorPrivate *p = i.d;
+
+ QDeclarativeIncubator::IncubationMode mode = i.incubationMode();
+
+ if (mode == QDeclarativeIncubator::AsynchronousIfNested) {
+ mode = QDeclarativeIncubator::Synchronous;
+
+ // Need to find the first constructing context and see if it is asynchronous
+ QDeclarativeIncubatorPrivate *parentIncubator = 0;
+ QDeclarativeContextData *cctxt = forContext;
+ while (cctxt) {
+ if (cctxt->activeVME) {
+ parentIncubator = (QDeclarativeIncubatorPrivate *)cctxt->activeVME->data;
+ break;
+ }
+ cctxt = cctxt->parent;
+ }
+
+ if (parentIncubator && parentIncubator->mode != QDeclarativeIncubator::Synchronous) {
+ mode = QDeclarativeIncubator::Asynchronous;
+ p->waitingOnMe = parentIncubator;
+ parentIncubator->waitingFor.insert(p);
+ }
+ }
+
+ if (mode == QDeclarativeIncubator::Synchronous) {
+ QDeclarativeVME::Interrupt i;
+ p->incubate(i);
+ } else {
+ inProgressCreations++;
+ incubatorList.insert(p);
+ incubatorCount++;
+
+ if (incubationController)
+ incubationController->incubatingObjectCountChanged(incubatorCount);
+ }
+}
+
+void QDeclarativeEngine::setIncubationController(QDeclarativeIncubationController *i)
+{
+ Q_D(QDeclarativeEngine);
+ d->incubationController = i;
+ if (i) i->d = d;
+}
+
+QDeclarativeIncubationController *QDeclarativeEngine::incubationController() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->incubationController;
+}
+
+QDeclarativeIncubatorPrivate::QDeclarativeIncubatorPrivate(QDeclarativeIncubator *q,
+ QDeclarativeIncubator::IncubationMode m)
+: q(q), mode(m), progress(Execute), result(0), component(0), vme(this), waitingOnMe(0)
+{
+}
+
+QDeclarativeIncubatorPrivate::~QDeclarativeIncubatorPrivate()
+{
+ clear();
+}
+
+void QDeclarativeIncubatorPrivate::clear()
+{
+ if (next.isInList()) {
+ next.remove();
+ Q_ASSERT(component);
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(component->engine);
+ component->release();
+
+ enginePriv->incubatorCount--;
+ QDeclarativeIncubationController *controller = enginePriv->incubationController;
+ if (controller)
+ controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
+ }
+
+ if (nextWaitingFor.isInList()) {
+ Q_ASSERT(waitingOnMe);
+ nextWaitingFor.remove();
+ waitingOnMe = 0;
+ }
+
+}
+
+QDeclarativeIncubationController::QDeclarativeIncubationController()
+: d(0)
+{
+}
+
+QDeclarativeIncubationController::~QDeclarativeIncubationController()
+{
+ if (d) QDeclarativeEnginePrivate::get(d)->setIncubationController(0);
+ d = 0;
+}
+
+QDeclarativeEngine *QDeclarativeIncubationController::engine() const
+{
+ return QDeclarativeEnginePrivate::get(d);
+}
+
+int QDeclarativeIncubationController::incubatingObjectCount() const
+{
+ if (d)
+ return d->incubatorCount;
+ else
+ return 0;
+}
+
+void QDeclarativeIncubationController::incubatingObjectCountChanged(int)
+{
+}
+
+void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i)
+{
+ QDeclarativeEngine *engine = component->engine;
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+
+ if (progress == QDeclarativeIncubatorPrivate::Execute) {
+ enginePriv->referenceScarceResources();
+ result = vme.execute(&errors, i);
+ enginePriv->dereferenceScarceResources();
+
+ if (errors.isEmpty() && result == 0)
+ return; // Interrupted
+
+ if (result) {
+ QDeclarativeData *ddata = QDeclarativeData::get(result);
+ Q_ASSERT(ddata);
+ ddata->indestructible = true;
+
+ q->setInitialState(result);
+ }
+
+ if (errors.isEmpty())
+ progress = QDeclarativeIncubatorPrivate::Completing;
+ else
+ progress = QDeclarativeIncubatorPrivate::Completed;
+
+ q->statusChanged(q->status());
+
+ if (i.shouldInterrupt())
+ goto finishIncubate;
+ }
+
+ if (progress == QDeclarativeIncubatorPrivate::Completing) {
+ do {
+ if (vme.complete(i)) {
+ progress = QDeclarativeIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+ } while (!i.shouldInterrupt());
+ }
+
+finishIncubate:
+ if (progress == QDeclarativeIncubatorPrivate::Completed && waitingFor.isEmpty()) {
+ QDeclarativeIncubatorPrivate *isWaiting = waitingOnMe;
+ clear();
+ if (isWaiting) isWaiting->incubate(i);
+
+ enginePriv->inProgressCreations--;
+
+ q->statusChanged(q->status());
+
+ if (0 == enginePriv->inProgressCreations) {
+ while (enginePriv->erroredBindings) {
+ enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->erroredBindings->removeError();
+ }
+ }
+ }
+}
+
+void QDeclarativeIncubationController::incubateFor(int msecs)
+{
+ if (!d || d->incubatorCount == 0)
+ return;
+
+ QDeclarativeVME::Interrupt i(msecs * 1000000);
+ i.reset();
+ do {
+ QDeclarativeIncubatorPrivate *p = (QDeclarativeIncubatorPrivate*)d->incubatorList.first();
+ p->incubate(i);
+ } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
+}
+
+void QDeclarativeIncubationController::incubateWhile(bool *flag)
+{
+ if (!d || d->incubatorCount == 0)
+ return;
+
+ QDeclarativeVME::Interrupt i(flag);
+ do {
+ QDeclarativeIncubatorPrivate *p = (QDeclarativeIncubatorPrivate*)d->incubatorList.first();
+ p->incubate(i);
+ } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
+}
+
+QDeclarativeIncubator::QDeclarativeIncubator(IncubationMode m)
+: d(new QDeclarativeIncubatorPrivate(this, m))
+{
+}
+
+QDeclarativeIncubator::~QDeclarativeIncubator()
+{
+ delete d; d = 0;
+}
+
+void QDeclarativeIncubator::clear()
+{
+}
+
+void QDeclarativeIncubator::forceIncubation()
+{
+ QDeclarativeVME::Interrupt i;
+ while (Loading == status()) {
+ while (Loading == status() && !d->waitingFor.isEmpty())
+ d->waitingFor.first()->incubate(i);
+ if (Loading == status())
+ d->incubate(i);
+ }
+
+}
+
+bool QDeclarativeIncubator::isNull() const
+{
+ return status() == Null;
+}
+
+bool QDeclarativeIncubator::isReady() const
+{
+ return status() == Ready;
+}
+
+bool QDeclarativeIncubator::isError() const
+{
+ return status() == Error;
+}
+
+bool QDeclarativeIncubator::isLoading() const
+{
+ return status() == Loading;
+}
+
+QList<QDeclarativeError> QDeclarativeIncubator::errors() const
+{
+ return d->errors;
+}
+
+QDeclarativeIncubator::IncubationMode QDeclarativeIncubator::incubationMode() const
+{
+ return d->mode;
+}
+
+QDeclarativeIncubator::Status QDeclarativeIncubator::status() const
+{
+ if (!d->errors.isEmpty()) return Error;
+ else if (d->result && d->progress == QDeclarativeIncubatorPrivate::Completed &&
+ d->waitingFor.isEmpty()) return Ready;
+ else if (d->component) return Loading;
+ else return Null;
+}
+
+QObject *QDeclarativeIncubator::object() const
+{
+ if (status() != Ready) return 0;
+ else return d->result;
+}
+
+void QDeclarativeIncubator::statusChanged(Status)
+{
+}
+
+void QDeclarativeIncubator::setInitialState(QObject *)
+{
+}
diff --git a/src/declarative/qml/qdeclarativeincubator.h b/src/declarative/qml/qdeclarativeincubator.h
new file mode 100644
index 0000000000..5b57cc82c1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeincubator.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEINCUBATOR_H
+#define QDECLARATIVEINCUBATOR_H
+
+#include <QtDeclarative/qdeclarativeerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+
+class QDeclarativeIncubatorPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeIncubator
+{
+ Q_DISABLE_COPY(QDeclarativeIncubator);
+public:
+ enum IncubationMode {
+ Asynchronous,
+ AsynchronousIfNested,
+ Synchronous
+ };
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ QDeclarativeIncubator(IncubationMode = Asynchronous);
+ virtual ~QDeclarativeIncubator();
+
+ void clear();
+ void forceIncubation();
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ QList<QDeclarativeError> errors() const;
+
+ IncubationMode incubationMode() const;
+
+ Status status() const;
+
+ QObject *object() const;
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+
+private:
+ friend class QDeclarativeComponent;
+ friend class QDeclarativeEnginePrivate;
+ friend class QDeclarativeIncubatorPrivate;
+ QDeclarativeIncubatorPrivate *d;
+};
+
+class QDeclarativeEnginePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeIncubationController
+{
+ Q_DISABLE_COPY(QDeclarativeIncubationController);
+public:
+ QDeclarativeIncubationController();
+ virtual ~QDeclarativeIncubationController();
+
+ QDeclarativeEngine *engine() const;
+ int incubatingObjectCount() const;
+
+ void incubateFor(int msecs);
+ void incubateWhile(bool *flag);
+
+protected:
+ virtual void incubatingObjectCountChanged(int);
+
+private:
+ friend class QDeclarativeEngine;
+ friend class QDeclarativeEnginePrivate;
+ friend class QDeclarativeIncubatorPrivate;
+ QDeclarativeEnginePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEINCUBATOR_H
diff --git a/src/declarative/qml/ftw/qdeclarativerefcount.cpp b/src/declarative/qml/qdeclarativeincubator_p.h
index a17d5b7142..8210f6d3f6 100644
--- a/src/declarative/qml/ftw/qdeclarativerefcount.cpp
+++ b/src/declarative/qml/qdeclarativeincubator_p.h
@@ -39,32 +39,58 @@
**
****************************************************************************/
-#include "private/qdeclarativerefcount_p.h"
+#ifndef QDECLARATIVEINCUBATOR_P_H
+#define QDECLARATIVEINCUBATOR_P_H
+
+#include <private/qintrusivelist_p.h>
+#include <private/qdeclarativevme_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
QT_BEGIN_NAMESPACE
-QDeclarativeRefCount::QDeclarativeRefCount()
-: refCount(1)
+class QDeclarativeCompiledData;
+class QDeclarativeIncubator;
+class QDeclarativeIncubatorPrivate : public QDeclarativeEnginePrivate::Incubator
{
-}
+ QIntrusiveListNode nextWaitingFor;
+public:
+ QDeclarativeIncubatorPrivate(QDeclarativeIncubator *q, QDeclarativeIncubator::IncubationMode m);
+ ~QDeclarativeIncubatorPrivate();
-QDeclarativeRefCount::~QDeclarativeRefCount()
-{
-}
+ QDeclarativeIncubator *q;
-void QDeclarativeRefCount::addref()
-{
- Q_ASSERT(refCount > 0);
- ++refCount;
-}
+ QDeclarativeIncubator::IncubationMode mode;
-void QDeclarativeRefCount::release()
-{
- Q_ASSERT(refCount > 0);
- --refCount;
- if (refCount == 0)
- delete this;
-}
+ QList<QDeclarativeError> errors;
+
+ enum Progress { Execute, Completing, Completed };
+ Progress progress;
+
+ QObject *result;
+ QDeclarativeCompiledData *component;
+ QDeclarativeVME vme;
+
+ typedef QDeclarativeIncubatorPrivate QIP;
+ QIP *waitingOnMe;
+ QIntrusiveList<QIP, &QIP::nextWaitingFor> waitingFor;
+
+ void clear();
+
+ void incubate(QDeclarativeVME::Interrupt &i);
+};
QT_END_NAMESPACE
+#endif // QDECLARATIVEINCUBATOR_P_H
+
diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp
index 3093ddc8ac..3d505c7f1f 100644
--- a/src/declarative/qml/qdeclarativeinstruction.cpp
+++ b/src/declarative/qml/qdeclarativeinstruction.cpp
@@ -57,11 +57,20 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
case QDeclarativeInstruction::Init:
qWarning().nospace() << idx << "\t\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding;
break;
+ case QDeclarativeInstruction::DeferInit:
+ qWarning().nospace() << idx << "\t\t" << "DEFER_INIT\t\t" << instr->deferInit.bindingsSize << "\t" << instr->deferInit.parserStatusSize;
+ break;
case QDeclarativeInstruction::Done:
qWarning().nospace() << idx << "\t\t" << "DONE";
break;
- case QDeclarativeInstruction::CreateObject:
- qWarning().nospace() << idx << "\t\t" << "CREATE\t\t\t" << instr->create.type << "\t" << instr->create.bindingBits << "\t\t" << types.at(instr->create.type).className;
+ case QDeclarativeInstruction::CreateCppObject:
+ qWarning().nospace() << idx << "\t\t" << "CREATECPP\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className;
+ break;
+ case QDeclarativeInstruction::CreateQMLObject:
+ qWarning().nospace() << idx << "\t\t" << "CREATEQML\t\t\t" << instr->createQml.type << "\t" << instr->createQml.bindingBits << "\t\t" << types.at(instr->createQml.type).className;
+ break;
+ case QDeclarativeInstruction::CompleteQMLObject:
+ qWarning().nospace() << idx << "\t\t" << "COMPLETEQML";
break;
case QDeclarativeInstruction::CreateSimpleObject:
qWarning().nospace() << idx << "\t\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize;
@@ -166,7 +175,7 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope << "\t" << instr->storeScriptString.bindingId;
break;
case QDeclarativeInstruction::AssignSignalObject:
- qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal);
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << primitives.at(instr->assignSignalObject.signal);
break;
case QDeclarativeInstruction::AssignCustomType:
qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h
index 35de8b2a91..e64ca5d3c7 100644
--- a/src/declarative/qml/qdeclarativeinstruction_p.h
+++ b/src/declarative/qml/qdeclarativeinstruction_p.h
@@ -59,8 +59,11 @@ QT_BEGIN_NAMESPACE
#define FOR_EACH_QML_INSTR(F) \
F(Init, init) \
+ F(DeferInit, deferInit) \
F(Done, common) \
- F(CreateObject, create) \
+ F(CreateCppObject, create) \
+ F(CreateQMLObject, createQml) \
+ F(CompleteQMLObject, completeQml) \
F(CreateSimpleObject, createSimple) \
F(SetId, setId) \
F(SetDefault, common) \
@@ -151,14 +154,35 @@ union QDeclarativeInstruction
int parserStatusSize;
int contextCache;
int compiledBinding;
+ int objectStackSize;
+ int listStackSize;
+ };
+ struct instr_deferInit {
+ QML_INSTR_HEADER
+ int bindingsSize;
+ int parserStatusSize;
+ int objectStackSize;
+ int listStackSize;
+ };
+ struct instr_createQml {
+ QML_INSTR_HEADER
+ int type;
+ int bindingBits;
+ bool isRoot;
+ };
+ struct instr_completeQml {
+ QML_INSTR_HEADER
+ ushort column;
+ ushort line;
+ bool isRoot;
};
struct instr_create {
QML_INSTR_HEADER
int type;
int data;
- int bindingBits;
ushort column;
ushort line;
+ bool isRoot;
};
struct instr_createSimple {
QML_INSTR_HEADER
@@ -203,6 +227,7 @@ union QDeclarativeInstruction
int value;
short context;
short owner;
+ bool isRoot;
ushort line;
};
struct instr_fetch {
@@ -357,6 +382,7 @@ union QDeclarativeInstruction
int metaObject;
ushort column;
ushort line;
+ bool isRoot;
};
struct instr_fetchAttached {
QML_INSTR_HEADER
@@ -425,7 +451,10 @@ union QDeclarativeInstruction
instr_common common;
instr_init init;
+ instr_deferInit deferInit;
instr_create create;
+ instr_createQml createQml;
+ instr_completeQml completeQml;
instr_createSimple createSimple;
instr_storeMeta storeMeta;
instr_setId setId;
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index e35fa52eed..6337750335 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -200,7 +200,7 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m)
Creates a new empty QDeclarativePropertyCache.
*/
QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0)
+: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0)
{
Q_ASSERT(engine);
}
@@ -209,7 +209,7 @@ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e)
Creates a new QDeclarativePropertyCache of \a metaObject.
*/
QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject)
-: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0)
+: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0)
{
Q_ASSERT(engine);
Q_ASSERT(metaObject);
@@ -223,6 +223,16 @@ QDeclarativePropertyCache::~QDeclarativePropertyCache()
if (parent) parent->release();
parent = 0;
+ engine = 0;
+}
+
+void QDeclarativePropertyCache::destroy()
+{
+ Q_ASSERT(engine || constructor.IsEmpty());
+ if (constructor.IsEmpty())
+ delete this;
+ else
+ QDeclarativeEnginePrivate::deleteInEngineThread(engine, this);
}
// This is inherited from QDeclarativeCleanup, so it should only clear the things
@@ -305,8 +315,7 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags)
{
Q_UNUSED(revision);
-
- qPersistentDispose(constructor); // Now invalid
+ Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
bool dynamicMetaObject = isDynamicMetaObject(metaObject);
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index 33565c4d45..fefcf7f6d0 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -198,7 +198,9 @@ public:
static Data *property(QDeclarativeEngine *, QObject *, const QHashedV8String &, Data &);
static bool isDynamicMetaObject(const QMetaObject *);
+
protected:
+ virtual void destroy();
virtual void clear();
private:
diff --git a/src/declarative/qml/qdeclarativescript.cpp b/src/declarative/qml/qdeclarativescript.cpp
index 55a6b2b2cf..9e6e09ed0c 100644
--- a/src/declarative/qml/qdeclarativescript.cpp
+++ b/src/declarative/qml/qdeclarativescript.cpp
@@ -307,7 +307,6 @@ bool QDeclarativeScript::Variant::asBoolean() const
QString QDeclarativeScript::Variant::asString() const
{
if (t == String) {
- // XXX aakenned
return l->value.toString();
} else {
return asWritten.toString();
@@ -379,7 +378,6 @@ QString QDeclarativeScript::Variant::asScript() const
return escapedString(asString());
case Script:
if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(n)) {
- // XXX aakenned
return i->name.toString();
} else
return asWritten.toString();
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index 8bb40ce7a5..ebda11fa31 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -42,24 +42,117 @@
#include "qdeclarativetypeloader_p.h"
#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativethread_p.h>
#include <private/qdeclarativecompiler_p.h>
#include <private/qdeclarativecomponent_p.h>
-#include <private/qdeclarativeglobal_p.h>
#include <private/qdeclarativedebugtrace_p.h>
-#include <QtDeclarative/qdeclarativecomponent.h>
-#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
#include <QtCore/qdiriterator.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeextensioninterface.h>
#if defined (Q_OS_UNIX)
#include <sys/types.h>
#include <dirent.h>
#endif
+// #define DATABLOB_DEBUG
+
+#ifdef DATABLOB_DEBUG
+
+#define ASSERT_MAINTHREAD() do { if(m_thread->isThisThread()) qFatal("QDeclarativeDataLoader: Caller not in main thread"); } while(false)
+#define ASSERT_LOADTHREAD() do { if(!m_thread->isThisThread()) qFatal("QDeclarativeDataLoader: Caller not in load thread"); } while(false)
+#define ASSERT_CALLBACK() do { if(!m_manager || !m_manager->m_thread->isThisThread()) qFatal("QDeclarativeDataBlob: An API call was made outside a callback"); } while(false)
+
+#else
+
+#define ASSERT_MAINTHREAD()
+#define ASSERT_LOADTHREAD()
+#define ASSERT_CALLBACK()
+
+#endif
+
QT_BEGIN_NAMESPACE
+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QDeclarativeDataLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QDeclarativeDataLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeDataLoaderNetworkReplyProxy(QDeclarativeDataLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+private:
+ QDeclarativeDataLoader *l;
+};
+
+class QDeclarativeDataLoaderThread : public QDeclarativeThread
+{
+ typedef QDeclarativeDataLoaderThread This;
+
+public:
+ QDeclarativeDataLoaderThread(QDeclarativeDataLoader *loader);
+ QNetworkAccessManager *networkAccessManager() const;
+ QDeclarativeDataLoaderNetworkReplyProxy *networkReplyProxy() const;
+
+ void load(QDeclarativeDataBlob *b);
+ void loadAsync(QDeclarativeDataBlob *b);
+ void loadWithStaticData(QDeclarativeDataBlob *b, const QByteArray &);
+ void loadWithStaticDataAsync(QDeclarativeDataBlob *b, const QByteArray &);
+ void callCompleted(QDeclarativeDataBlob *b);
+ void callDownloadProgressChanged(QDeclarativeDataBlob *b, qreal p);
+ void initializeEngine(QDeclarativeExtensionInterface *, const char *);
+
+protected:
+ virtual void shutdownThread();
+
+private:
+ void loadThread(QDeclarativeDataBlob *b);
+ void loadWithStaticDataThread(QDeclarativeDataBlob *b, const QByteArray &);
+ void callCompletedMain(QDeclarativeDataBlob *b);
+ void callDownloadProgressChangedMain(QDeclarativeDataBlob *b, qreal p);
+ void initializeEngineMain(QDeclarativeExtensionInterface *iface, const char *uri);
+
+ QDeclarativeDataLoader *m_loader;
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QDeclarativeDataLoaderNetworkReplyProxy *m_networkReplyProxy;
+};
+
+
+QDeclarativeDataLoaderNetworkReplyProxy::QDeclarativeDataLoaderNetworkReplyProxy(QDeclarativeDataLoader *l)
+: l(l)
+{
+}
+
+void QDeclarativeDataLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QDeclarativeDataLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
/*
Returns the set of QML files in path (qmldir, *.qml, *.js). The caller
@@ -182,8 +275,8 @@ This enum describes the type of the data blob.
Create a new QDeclarativeDataBlob for \a url and of the provided \a type.
*/
QDeclarativeDataBlob::QDeclarativeDataBlob(const QUrl &url, Type type)
-: m_type(type), m_status(Null), m_progress(0), m_url(url), m_finalUrl(url), m_manager(0),
- m_redirectCount(0), m_inCallback(false), m_isDone(false)
+: m_type(type), m_url(url), m_finalUrl(url), m_manager(0), m_redirectCount(0),
+ m_inCallback(false), m_isDone(false)
{
}
@@ -208,7 +301,7 @@ Returns the blob's status.
*/
QDeclarativeDataBlob::Status QDeclarativeDataBlob::status() const
{
- return m_status;
+ return m_data.status();
}
/*!
@@ -216,7 +309,7 @@ Returns true if the status is Null.
*/
bool QDeclarativeDataBlob::isNull() const
{
- return m_status == Null;
+ return status() == Null;
}
/*!
@@ -224,7 +317,7 @@ Returns true if the status is Loading.
*/
bool QDeclarativeDataBlob::isLoading() const
{
- return m_status == Loading;
+ return status() == Loading;
}
/*!
@@ -232,7 +325,7 @@ Returns true if the status is WaitingForDependencies.
*/
bool QDeclarativeDataBlob::isWaiting() const
{
- return m_status == WaitingForDependencies;
+ return status() == WaitingForDependencies;
}
/*!
@@ -240,7 +333,7 @@ Returns true if the status is Complete.
*/
bool QDeclarativeDataBlob::isComplete() const
{
- return m_status == Complete;
+ return status() == Complete;
}
/*!
@@ -248,7 +341,7 @@ Returns true if the status is Error.
*/
bool QDeclarativeDataBlob::isError() const
{
- return m_status == Error;
+ return status() == Error;
}
/*!
@@ -256,7 +349,8 @@ Returns true if the status is Complete or Error.
*/
bool QDeclarativeDataBlob::isCompleteOrError() const
{
- return isComplete() || isError();
+ Status s = status();
+ return s == Error || s == Complete;
}
/*!
@@ -264,7 +358,9 @@ Returns the data download progress from 0 to 1.
*/
qreal QDeclarativeDataBlob::progress() const
{
- return m_progress;
+ quint8 p = m_data.progress();
+ if (p == 0xFF) return 1.;
+ else return qreal(p) / qreal(0xFF);
}
/*!
@@ -282,17 +378,23 @@ QUrl QDeclarativeDataBlob::url() const
Returns the final url of the data. Initially this is the same as
url(), but if a network redirect happens while fetching the data, this url
is updated to reflect the new location.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
*/
QUrl QDeclarativeDataBlob::finalUrl() const
{
+ Q_ASSERT(isCompleteOrError() || (m_manager && m_manager->m_thread->isThisThread()));
return m_finalUrl;
}
/*!
Return the errors on this blob.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
*/
QList<QDeclarativeError> QDeclarativeDataBlob::errors() const
{
+ Q_ASSERT(isCompleteOrError() || (m_manager && m_manager->m_thread->isThisThread()));
return m_errors;
}
@@ -300,11 +402,14 @@ QList<QDeclarativeError> QDeclarativeDataBlob::errors() const
Mark this blob as having \a errors.
All outstanding dependencies will be cancelled. Requests to add new dependencies
-will be ignored. Entry into the Error state is irreversable, although you can change the
-specific errors by additional calls to setError.
+will be ignored. Entry into the Error state is irreversable.
+
+The setError() method may only be called from within a QDeclarativeDataBlob callback.
*/
void QDeclarativeDataBlob::setError(const QDeclarativeError &errors)
{
+ ASSERT_CALLBACK();
+
QList<QDeclarativeError> l;
l << errors;
setError(l);
@@ -315,8 +420,13 @@ void QDeclarativeDataBlob::setError(const QDeclarativeError &errors)
*/
void QDeclarativeDataBlob::setError(const QList<QDeclarativeError> &errors)
{
- m_status = Error;
- m_errors = errors;
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Error);
+ Q_ASSERT(m_errors.isEmpty());
+
+ m_errors = errors; // Must be set before the m_data fence
+ m_data.setStatus(Error);
cancelAllWaitingFor();
@@ -327,19 +437,25 @@ void QDeclarativeDataBlob::setError(const QList<QDeclarativeError> &errors)
/*!
Wait for \a blob to become complete or to error. If \a blob is already
complete or in error, or this blob is already complete, this has no effect.
+
+The setError() method may only be called from within a QDeclarativeDataBlob callback.
*/
void QDeclarativeDataBlob::addDependency(QDeclarativeDataBlob *blob)
{
+ ASSERT_CALLBACK();
+
Q_ASSERT(status() != Null);
if (!blob ||
blob->status() == Error || blob->status() == Complete ||
- status() == Error || status() == Complete ||
+ status() == Error || status() == Complete || m_isDone ||
m_waitingFor.contains(blob))
return;
blob->addref();
- m_status = WaitingForDependencies;
+
+ m_data.setStatus(WaitingForDependencies);
+
m_waitingFor.append(blob);
blob->m_waitingOnMe.append(this);
}
@@ -360,6 +476,9 @@ You can set an error in this method, but you cannot add new dependencies. Imple
should use this callback to finalize processing of data.
The default implementation does nothing.
+
+XXX Rename processData() or some such to avoid confusion between done() (processing thread)
+and completed() (main thread)
*/
void QDeclarativeDataBlob::done()
{
@@ -451,22 +570,63 @@ void QDeclarativeDataBlob::allDependenciesDone()
/*!
Called when the download progress of this blob changes. \a progress goes
from 0 to 1.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
*/
void QDeclarativeDataBlob::downloadProgressChanged(qreal progress)
{
Q_UNUSED(progress);
}
+/*!
+Invoked on the main thread sometime after done() was called on the load thread.
+
+You cannot modify the blobs state at all in this callback and cannot depend on the
+order or timeliness of these callbacks. Implementors should use this callback to notify
+dependencies on the main thread that the blob is done and not a lot else.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QDeclarativeDataBlob::completed()
+{
+}
+
+
void QDeclarativeDataBlob::tryDone()
{
if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
- if (status() != Error)
- m_status = Complete;
-
m_isDone = true;
addref();
+
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataBlob::done() %s", qPrintable(url().toString()));
+#endif
done();
+
+ if (status() != Error)
+ m_data.setStatus(Complete);
+
notifyAllWaitingOnMe();
+
+ // Locking is not required here, as anyone expecting callbacks must
+ // already be protected against the blob being completed (as set above);
+ if (m_data.isAsync()) {
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataBlob: Dispatching completed");
+#endif
+ m_manager->m_thread->callCompleted(this);
+ }
+
release();
}
}
@@ -519,6 +679,170 @@ void QDeclarativeDataBlob::notifyComplete(QDeclarativeDataBlob *blob)
tryDone();
}
+#define TD_STATUS_MASK 0x0000FFFF
+#define TD_STATUS_SHIFT 0
+#define TD_PROGRESS_MASK 0x00FF0000
+#define TD_PROGRESS_SHIFT 16
+#define TD_ASYNC_MASK 0x80000000
+
+QDeclarativeDataBlob::ThreadData::ThreadData()
+: _p(0)
+{
+}
+
+QDeclarativeDataBlob::Status QDeclarativeDataBlob::ThreadData::status() const
+{
+ return QDeclarativeDataBlob::Status((_p & TD_STATUS_MASK) >> TD_STATUS_SHIFT);
+}
+
+void QDeclarativeDataBlob::ThreadData::setStatus(QDeclarativeDataBlob::Status status)
+{
+ while (true) {
+ int d = _p;
+ int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+bool QDeclarativeDataBlob::ThreadData::isAsync() const
+{
+ return _p & TD_ASYNC_MASK;
+}
+
+void QDeclarativeDataBlob::ThreadData::setIsAsync(bool v)
+{
+ while (true) {
+ int d = _p;
+ int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+quint8 QDeclarativeDataBlob::ThreadData::progress() const
+{
+ return quint8((_p & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT);
+}
+
+void QDeclarativeDataBlob::ThreadData::setProgress(quint8 v)
+{
+ while (true) {
+ int d = _p;
+ int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+QDeclarativeDataLoaderThread::QDeclarativeDataLoaderThread(QDeclarativeDataLoader *loader)
+: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0)
+{
+}
+
+QNetworkAccessManager *QDeclarativeDataLoaderThread::networkAccessManager() const
+{
+ Q_ASSERT(isThisThread());
+ if (!m_networkAccessManager) {
+ m_networkAccessManager = QDeclarativeEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(0);
+ m_networkReplyProxy = new QDeclarativeDataLoaderNetworkReplyProxy(m_loader);
+ }
+
+ return m_networkAccessManager;
+}
+
+QDeclarativeDataLoaderNetworkReplyProxy *QDeclarativeDataLoaderThread::networkReplyProxy() const
+{
+ Q_ASSERT(isThisThread());
+ Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
+ return m_networkReplyProxy;
+}
+
+void QDeclarativeDataLoaderThread::load(QDeclarativeDataBlob *b)
+{
+ b->addref();
+ callMethodInThread(&This::loadThread, b);
+}
+
+void QDeclarativeDataLoaderThread::loadAsync(QDeclarativeDataBlob *b)
+{
+ b->addref();
+ postMethodToThread(&This::loadThread, b);
+}
+
+void QDeclarativeDataLoaderThread::loadWithStaticData(QDeclarativeDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QDeclarativeDataLoaderThread::loadWithStaticDataAsync(QDeclarativeDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QDeclarativeDataLoaderThread::callCompleted(QDeclarativeDataBlob *b)
+{
+ b->addref();
+ postMethodToMain(&This::callCompletedMain, b);
+}
+
+void QDeclarativeDataLoaderThread::callDownloadProgressChanged(QDeclarativeDataBlob *b, qreal p)
+{
+ b->addref();
+ postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
+}
+
+void QDeclarativeDataLoaderThread::initializeEngine(QDeclarativeExtensionInterface *iface,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineMain, iface, uri);
+}
+
+void QDeclarativeDataLoaderThread::shutdownThread()
+{
+ delete m_networkAccessManager;
+ m_networkAccessManager = 0;
+ delete m_networkReplyProxy;
+ m_networkReplyProxy = 0;
+}
+
+void QDeclarativeDataLoaderThread::loadThread(QDeclarativeDataBlob *b)
+{
+ m_loader->loadThread(b);
+ b->release();
+}
+
+void QDeclarativeDataLoaderThread::loadWithStaticDataThread(QDeclarativeDataBlob *b, const QByteArray &d)
+{
+ m_loader->loadWithStaticDataThread(b, d);
+ b->release();
+}
+
+void QDeclarativeDataLoaderThread::callCompletedMain(QDeclarativeDataBlob *b)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataLoaderThread: %s completed() callback", qPrintable(b->url().toString()));
+#endif
+ b->completed();
+ b->release();
+}
+
+void QDeclarativeDataLoaderThread::callDownloadProgressChangedMain(QDeclarativeDataBlob *b, qreal p)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataLoaderThread: %s downloadProgressChanged(%f) callback",
+ qPrintable(b->url().toString()), p);
+#endif
+ b->downloadProgressChanged(p);
+ b->release();
+}
+
+void QDeclarativeDataLoaderThread::initializeEngineMain(QDeclarativeExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
/*!
\class QDeclarativeDataLoader
\brief The QDeclarativeDataLoader class abstracts loading files and their dependencies over the network.
@@ -553,7 +877,7 @@ Thus QDeclarativeDataBlob::done() will always eventually be called, even if the
Create a new QDeclarativeDataLoader for \a engine.
*/
QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine)
-: m_engine(engine)
+: m_engine(engine), m_thread(new QDeclarativeDataLoaderThread(this))
{
}
@@ -562,17 +886,105 @@ QDeclarativeDataLoader::~QDeclarativeDataLoader()
{
for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
(*iter)->release();
+
+ m_thread->shutdown();
+ delete m_thread;
+}
+
+void QDeclarativeDataLoader::lock()
+{
+ m_thread->lock();
+}
+
+void QDeclarativeDataLoader::unlock()
+{
+ m_thread->unlock();
}
/*!
Load the provided \a blob from the network or filesystem.
+
+The loader must be locked.
+*/
+void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob, Mode mode)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataLoader::load(%s): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
+ Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
+ Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_data.setStatus(QDeclarativeDataBlob::Loading);
+ blob->m_manager = this;
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadThread(blob);
+ lock();
+ } else if (mode == PreferSynchronous) {
+ unlock();
+ m_thread->load(blob);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ } else {
+ Q_ASSERT(mode == Asynchronous);
+ blob->m_data.setIsAsync(true);
+ unlock();
+ m_thread->loadAsync(blob);
+ lock();
+ }
+}
+
+/*!
+Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
+
+The loader must be locked.
*/
-void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
+void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data, Mode mode)
{
+#ifdef DATABLOB_DEBUG
+ qWarning("QDeclarativeDataLoader::loadWithStaticData(%s, data): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_data.setStatus(QDeclarativeDataBlob::Loading);
+ blob->m_manager = this;
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadWithStaticDataThread(blob, data);
+ lock();
+ } else if (mode == PreferSynchronous) {
+ unlock();
+ m_thread->loadWithStaticData(blob, data);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ } else {
+ Q_ASSERT(mode == Asynchronous);
+ blob->m_data.setIsAsync(true);
+ unlock();
+ m_thread->loadWithStaticDataAsync(blob, data);
+ lock();
+ }
+}
- blob->m_status = QDeclarativeDataBlob::Loading;
+void QDeclarativeDataLoader::loadWithStaticDataThread(QDeclarativeDataBlob *blob, const QByteArray &data)
+{
+ ASSERT_LOADTHREAD();
+
+ setData(blob, data);
+}
+
+void QDeclarativeDataLoader::loadThread(QDeclarativeDataBlob *blob)
+{
+ ASSERT_LOADTHREAD();
if (blob->m_url.isEmpty()) {
QDeclarativeError error;
@@ -595,8 +1007,9 @@ void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
if (file.open(QFile::ReadOnly)) {
QByteArray data = file.readAll();
- blob->m_progress = 1.;
- blob->downloadProgressChanged(1.);
+ blob->m_data.setProgress(0xFF);
+ if (blob->m_data.isAsync())
+ m_thread->callDownloadProgressChanged(blob, 1.);
setData(blob, data);
} else {
@@ -605,12 +1018,12 @@ void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
} else {
- blob->m_manager = this;
- QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url));
+ QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
+ QObject *nrp = m_thread->networkReplyProxy();
QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
- this, SLOT(networkReplyProgress(qint64,qint64)));
+ nrp, SLOT(downloadProgress(qint64,qint64)));
QObject::connect(reply, SIGNAL(finished()),
- this, SLOT(networkReplyFinished()));
+ nrp, SLOT(finished()));
m_networkReplies.insert(reply, blob);
blob->addref();
@@ -619,9 +1032,10 @@ void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
-void QDeclarativeDataLoader::networkReplyFinished()
+void QDeclarativeDataLoader::networkReplyFinished(QNetworkReply *reply)
{
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ Q_ASSERT(m_thread->isThisThread());
+
reply->deleteLater();
QDeclarativeDataBlob *blob = m_networkReplies.take(reply);
@@ -636,8 +1050,9 @@ void QDeclarativeDataLoader::networkReplyFinished()
QUrl url = reply->url().resolved(redirect.toUrl());
blob->m_finalUrl = url;
- QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url));
- QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
+ QObject *nrp = m_thread->networkReplyProxy();
+ QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
m_networkReplies.insert(reply, blob);
return;
}
@@ -653,40 +1068,49 @@ void QDeclarativeDataLoader::networkReplyFinished()
blob->release();
}
-void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal)
+void QDeclarativeDataLoader::networkReplyProgress(QNetworkReply *reply,
+ qint64 bytesReceived, qint64 bytesTotal)
{
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ Q_ASSERT(m_thread->isThisThread());
+
QDeclarativeDataBlob *blob = m_networkReplies.value(reply);
Q_ASSERT(blob);
if (bytesTotal != 0) {
- blob->m_progress = bytesReceived / bytesTotal;
- blob->downloadProgressChanged(blob->m_progress);
+ quint8 progress = 0xFF * (qreal(bytesReceived) / qreal(bytesTotal));
+ blob->m_data.setProgress(progress);
+ if (blob->m_data.isAsync())
+ m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
}
}
/*!
-Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
+Return the QDeclarativeEngine associated with this loader
*/
-void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data)
+QDeclarativeEngine *QDeclarativeDataLoader::engine() const
{
- Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
- Q_ASSERT(blob->m_manager == 0);
-
- blob->m_status = QDeclarativeDataBlob::Loading;
-
- setData(blob, data);
+ return m_engine;
}
/*!
-Return the QDeclarativeEngine associated with this loader
+Call the initializeEngine() method on \a iface. Used by QDeclarativeImportDatabase to ensure it
+gets called in the correct thread.
*/
-QDeclarativeEngine *QDeclarativeDataLoader::engine() const
+void QDeclarativeDataLoader::initializeEngine(QDeclarativeExtensionInterface *iface,
+ const char *uri)
{
- return m_engine;
+ Q_ASSERT(m_thread->isThisThread() || engine()->thread() == QThread::currentThread());
+
+ if (m_thread->isThisThread()) {
+ m_thread->initializeEngine(iface, uri);
+ } else {
+ Q_ASSERT(engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(engine(), uri);
+ }
}
+
void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data)
{
blob->m_inCallback = true;
@@ -696,8 +1120,8 @@ void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArra
if (!blob->isError() && !blob->isWaiting())
blob->allDependenciesDone();
- if (blob->status() != QDeclarativeDataBlob::Error)
- blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
+ if (blob->status() != QDeclarativeDataBlob::Error)
+ blob->m_data.setStatus(QDeclarativeDataBlob::WaitingForDependencies);
blob->m_inCallback = false;
@@ -741,6 +1165,8 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+ lock();
+
QDeclarativeTypeData *typeData = m_typeCache.value(url);
if (!typeData) {
@@ -750,6 +1176,9 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
}
typeData->addref();
+
+ unlock();
+
return typeData;
}
@@ -761,8 +1190,13 @@ The specified \a options control how the loader handles type data.
*/
QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
{
+ lock();
+
QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this);
QDeclarativeDataLoader::loadWithStaticData(typeData, data);
+
+ unlock();
+
return typeData;
}
@@ -775,6 +1209,8 @@ QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+ lock();
+
QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
if (!scriptBlob) {
@@ -783,6 +1219,10 @@ QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
QDeclarativeDataLoader::load(scriptBlob);
}
+ scriptBlob->addref();
+
+ unlock();
+
return scriptBlob;
}
@@ -795,6 +1235,8 @@ QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+ lock();
+
QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url);
if (!qmldirData) {
@@ -804,6 +1246,9 @@ QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
}
qmldirData->addref();
+
+ unlock();
+
return qmldirData;
}
@@ -914,6 +1359,7 @@ const QDeclarativeDirParser *QDeclarativeTypeLoader::qmlDirParser(const QString
return qmldirParser;
}
+
/*!
Clears cached information about loaded files, including any type data, scripts
and qmldir information.
@@ -1004,8 +1450,6 @@ void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback)
void QDeclarativeTypeData::done()
{
- addref();
-
// Check all script dependencies for errors
for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
@@ -1046,14 +1490,15 @@ void QDeclarativeTypeData::done()
if (!(m_options & QDeclarativeTypeLoader::PreserveParser))
scriptParser.clear();
+}
+void QDeclarativeTypeData::completed()
+{
// Notify callbacks
while (!m_callbacks.isEmpty()) {
TypeDataCallback *callback = m_callbacks.takeFirst();
callback->typeDataReady(this);
}
-
- release();
}
void QDeclarativeTypeData::dataReceived(const QByteArray &data)
@@ -1082,7 +1527,6 @@ void QDeclarativeTypeData::dataReceived(const QByteArray &data)
ref.location = import.location.start;
ref.qualifier = import.qualifier;
ref.script = blob;
- blob->addref();
m_scripts << ref;
}
@@ -1270,15 +1714,13 @@ QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
return 0;
}
-QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
-: QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeScript::Object::ScriptBlock::None),
- m_loaded(false)
+QDeclarativeScriptData::QDeclarativeScriptData()
+: importCache(0), pragmas(QDeclarativeScript::Object::ScriptBlock::None), m_loaded(false)
{
}
QDeclarativeScriptData::~QDeclarativeScriptData()
{
- clear();
}
void QDeclarativeScriptData::clear()
@@ -1294,6 +1736,9 @@ void QDeclarativeScriptData::clear()
qPersistentDispose(m_program);
qPersistentDispose(m_value);
+
+ // An addref() was made when the QDeclarativeCleanup was added to the engine.
+ release();
}
QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
@@ -1361,7 +1806,6 @@ void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
ref.location = import.location.start;
ref.qualifier = import.qualifier;
ref.script = blob;
- blob->addref();
m_scripts << ref;
} else {
Q_ASSERT(import.type == QDeclarativeScript::Import::Library);
@@ -1408,9 +1852,9 @@ void QDeclarativeScriptBlob::done()
return;
QDeclarativeEngine *engine = typeLoader()->engine();
- m_scriptData = new QDeclarativeScriptData(engine);
+ m_scriptData = new QDeclarativeScriptData();
m_scriptData->url = finalUrl();
- m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
+ m_scriptData->importCache = new QDeclarativeTypeNameCache();
for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
@@ -1422,13 +1866,7 @@ void QDeclarativeScriptBlob::done()
m_imports.populateCache(m_scriptData->importCache, engine);
m_scriptData->pragmas = m_pragmas;
-
- // XXX TODO: Handle errors that occur duing the script compile
- QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
- 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 = qPersistentNew<v8::Script>(program);
+ m_scriptData->m_programSource = m_source;
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
@@ -1451,3 +1889,4 @@ void QDeclarativeQmldirData::dataReceived(const QByteArray &data)
QT_END_NAMESPACE
+#include "qdeclarativetypeloader.moc"
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index af1a2f731e..1eaeebdbe6 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -54,17 +54,17 @@
//
#include <QtCore/qobject.h>
+#include <QtCore/qatomic.h>
#include <QtNetwork/qnetworkreply.h>
-#include <QtDeclarative/qjsvalue.h>
#include <QtDeclarative/qdeclarativeerror.h>
#include <QtDeclarative/qdeclarativeengine.h>
-#include <private/qdeclarativecleanup_p.h>
-#include <private/qdeclarativescript_p.h>
-#include <private/qdeclarativedirparser_p.h>
-#include <private/qdeclarativeimport_p.h>
-#include "private/qhashedstring_p.h"
#include <private/qv8_p.h>
+#include <private/qhashedstring_p.h>
+#include <private/qdeclarativescript_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativecleanup_p.h>
+#include <private/qdeclarativedirparser_p.h>
QT_BEGIN_NAMESPACE
@@ -76,6 +76,7 @@ class QDeclarativeCompiledData;
class QDeclarativeComponentPrivate;
class QDeclarativeTypeData;
class QDeclarativeDataLoader;
+class QDeclarativeExtensionInterface;
// Exported for QtQuick1
class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDataBlob : public QDeclarativeRefCount
@@ -115,33 +116,53 @@ public:
QList<QDeclarativeError> errors() const;
+protected:
+ // Can be called from within callbacks
void setError(const QDeclarativeError &);
void setError(const QList<QDeclarativeError> &errors);
-
void addDependency(QDeclarativeDataBlob *);
-protected:
+ // Callbacks made in load thread
virtual void dataReceived(const QByteArray &) = 0;
-
virtual void done();
virtual void networkError(QNetworkReply::NetworkError);
-
virtual void dependencyError(QDeclarativeDataBlob *);
virtual void dependencyComplete(QDeclarativeDataBlob *);
virtual void allDependenciesDone();
-
- virtual void downloadProgressChanged(qreal);
+ // Callbacks made in main thread
+ virtual void downloadProgressChanged(qreal);
+ virtual void completed();
private:
friend class QDeclarativeDataLoader;
+ friend class QDeclarativeDataLoaderThread;
+
void tryDone();
void cancelAllWaitingFor();
void notifyAllWaitingOnMe();
void notifyComplete(QDeclarativeDataBlob *);
+ struct ThreadData {
+ inline ThreadData();
+ inline QDeclarativeDataBlob::Status status() const;
+ inline void setStatus(QDeclarativeDataBlob::Status);
+ inline bool isAsync() const;
+ inline void setIsAsync(bool);
+ inline quint8 progress() const;
+ inline void setProgress(quint8);
+
+ private:
+ QAtomicInt _p;
+ };
+ ThreadData m_data;
+
+ // m_errors should *always* be written before the status is set to Error.
+ // We use the status change as a memory fence around m_errors so that locking
+ // isn't required. Once the status is set to Error (or Complete), m_errors
+ // cannot be changed.
+ QList<QDeclarativeError> m_errors;
+
Type m_type;
- Status m_status;
- qreal m_progress;
QUrl m_url;
QUrl m_finalUrl;
@@ -157,39 +178,52 @@ private:
int m_redirectCount:30;
bool m_inCallback:1;
bool m_isDone:1;
-
- QList<QDeclarativeError> m_errors;
};
+class QDeclarativeDataLoaderThread;
// Exported for QtQuick1
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDataLoader : public QObject
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDataLoader
{
- Q_OBJECT
public:
QDeclarativeDataLoader(QDeclarativeEngine *);
~QDeclarativeDataLoader();
- void load(QDeclarativeDataBlob *);
- void loadWithStaticData(QDeclarativeDataBlob *, const QByteArray &);
+ void lock();
+ void unlock();
- QDeclarativeEngine *engine() const;
+ bool isConcurrent() const { return true; }
+
+ enum Mode { PreferSynchronous, Asynchronous };
-private slots:
- void networkReplyFinished();
- void networkReplyProgress(qint64,qint64);
+ void load(QDeclarativeDataBlob *, Mode = PreferSynchronous);
+ void loadWithStaticData(QDeclarativeDataBlob *, const QByteArray &, Mode = PreferSynchronous);
+
+ QDeclarativeEngine *engine() const;
+ void initializeEngine(QDeclarativeExtensionInterface *, const char *);
private:
+ friend class QDeclarativeDataBlob;
+ friend class QDeclarativeDataLoaderThread;
+ friend class QDeclarativeDataLoaderNetworkReplyProxy;
+
+ void loadThread(QDeclarativeDataBlob *);
+ void loadWithStaticDataThread(QDeclarativeDataBlob *, const QByteArray &);
+ void networkReplyFinished(QNetworkReply *);
+ void networkReplyProgress(QNetworkReply *, qint64, qint64);
+
+ typedef QHash<QNetworkReply *, QDeclarativeDataBlob *> NetworkReplies;
+
void setData(QDeclarativeDataBlob *, const QByteArray &);
QDeclarativeEngine *m_engine;
- typedef QHash<QNetworkReply *, QDeclarativeDataBlob *> NetworkReplies;
+ QDeclarativeDataLoaderThread *m_thread;
NetworkReplies m_networkReplies;
};
// Exported for QtQuick1
class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader
{
- Q_OBJECT
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativeTypeLoader)
public:
QDeclarativeTypeLoader(QDeclarativeEngine *);
~QDeclarativeTypeLoader();
@@ -210,7 +244,6 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
const QDeclarativeDirParser *qmlDirParser(const QString &absoluteFilePath);
-
private:
typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
typedef QHash<QUrl, QDeclarativeScriptBlob *> ScriptCache;
@@ -275,6 +308,7 @@ public:
protected:
virtual void done();
+ virtual void completed();
virtual void dataReceived(const QByteArray &);
virtual void allDependenciesDone();
virtual void downloadProgressChanged(qreal);
@@ -303,10 +337,18 @@ private:
QDeclarativeTypeLoader *m_typeLoader;
};
-class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeRefCount, public QDeclarativeCleanup
+// QDeclarativeScriptData instances are created, uninitialized, by the loader in the
+// load thread. The first time they are used by the VME, they are initialized which
+// creates their v8 objects and they are referenced and added to the engine's cleanup
+// list. During QDeclarativeCleanup::clear() all v8 resources are destroyed, and the
+// reference that was created is released but final deletion only occurs once all the
+// references as released. This is all intended to ensure that the v8 resources are
+// only created and destroyed in the main thread :)
+class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeCleanup,
+ public QDeclarativeRefCount
{
public:
- QDeclarativeScriptData(QDeclarativeEngine *);
+ QDeclarativeScriptData();
~QDeclarativeScriptData();
QUrl url;
@@ -314,6 +356,9 @@ public:
QList<QDeclarativeScriptBlob *> scripts;
QDeclarativeScript::Object::ScriptBlock::Pragmas pragmas;
+ bool isInitialized() const { return hasEngine(); }
+ void initialize(QDeclarativeEngine *);
+
protected:
virtual void clear(); // From QDeclarativeCleanup
@@ -322,10 +367,9 @@ private:
friend class QDeclarativeScriptBlob;
bool m_loaded;
+ QString m_programSource;
v8::Persistent<v8::Script> m_program;
v8::Persistent<v8::Object> m_value;
-// QScriptProgram m_program;
-// QScriptValue m_value;
};
class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
index b7e4259b4c..31ad48a0dd 100644
--- a/src/declarative/qml/qdeclarativetypenamecache.cpp
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -45,21 +45,12 @@
QT_BEGIN_NAMESPACE
-QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+QDeclarativeTypeNameCache::QDeclarativeTypeNameCache()
{
}
QDeclarativeTypeNameCache::~QDeclarativeTypeNameCache()
{
- clear();
-}
-
-void QDeclarativeTypeNameCache::clear()
-{
- m_namedImports.clear();
- m_anonymousImports.clear();
- engine = 0;
}
void QDeclarativeTypeNameCache::add(const QHashedString &name, int importedScriptIndex)
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index a80bb6492c..219d07a5eb 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -65,10 +65,10 @@ QT_BEGIN_NAMESPACE
class QDeclarativeType;
class QDeclarativeEngine;
-class QDeclarativeTypeNameCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+class QDeclarativeTypeNameCache : public QDeclarativeRefCount
{
public:
- QDeclarativeTypeNameCache(QDeclarativeEngine *);
+ QDeclarativeTypeNameCache();
virtual ~QDeclarativeTypeNameCache();
inline bool isEmpty() const;
@@ -94,9 +94,6 @@ public:
Result query(const QHashedV8String &, const void *importNamespace);
QDeclarativeMetaType::ModuleApiInstance *moduleApi(const void *importNamespace);
-protected:
- virtual void clear();
-
private:
friend class QDeclarativeImports;
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 4ed7cf4464..d3748a4974 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -61,6 +61,7 @@
#include "private/qdeclarativev4bindings_p.h"
#include "private/qv8bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
+#include "private/qfinitestack_p.h"
#include "qdeclarativescriptstring.h"
#include "qdeclarativescriptstring_p.h"
@@ -78,78 +79,107 @@
QT_BEGIN_NAMESPACE
-// A simple stack wrapper around QVarLengthArray
-template<typename T>
-class QDeclarativeVMEStack : private QVarLengthArray<T, 128>
-{
-private:
- typedef QVarLengthArray<T, 128> VLA;
- int _index;
-
-public:
- inline QDeclarativeVMEStack();
- inline bool isEmpty() const;
- inline const T &top() const;
- inline void push(const T &o);
- inline T pop();
- inline int count() const;
- inline const T &at(int index) const;
-};
-
-// We do this so we can forward declare the type in the qdeclarativevme_p.h header
-class QDeclarativeVMEObjectStack : public QDeclarativeVMEStack<QObject *> {};
-
-QDeclarativeVME::QDeclarativeVME()
-{
-}
+using namespace QDeclarativeVMETypes;
#define VME_EXCEPTION(desc, line) \
{ \
QDeclarativeError error; \
error.setDescription(desc.trimmed()); \
error.setLine(line); \
- error.setUrl(comp->url); \
- vmeErrors << error; \
+ error.setUrl(COMP->url); \
+ *errors << error; \
goto exceptionExit; \
}
-struct ListInstance
+void QDeclarativeVME::init(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start)
{
- ListInstance()
- : type(0) {}
- ListInstance(int t)
- : type(t) {}
+ Q_ASSERT(ctxt);
+ Q_ASSERT(comp);
- int type;
- QDeclarativeListProperty<void> qListProperty;
-};
+ if (start == -1) start = 0;
-Q_DECLARE_TYPEINFO(ListInstance, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
+ State initState;
+ initState.context = ctxt;
+ initState.compiledData = comp;
+ initState.instructionStream = comp->bytecode.constData() + start;
+ states.push(initState);
-QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp,
- int start, const QBitField &bindingSkipList)
-{
- QDeclarativeVMEObjectStack stack;
+ typedef QDeclarativeInstruction I;
+ I *i = (I *)initState.instructionStream;
- if (start == -1) start = 0;
+ Q_ASSERT(comp->instructionType(i) == I::Init);
+
+ objects.allocate(i->init.objectStackSize);
+ lists.allocate(i->init.listStackSize);
+ bindValues.allocate(i->init.bindingsSize);
+ parserStatus.allocate(i->init.parserStatusSize);
- return run(stack, ctxt, comp, start, bindingSkipList);
+ rootContext = 0;
+ engine = ctxt->engine;
+ bindValuesCount = 0;
+ parserStatusCount = 0;
}
-void QDeclarativeVME::runDeferred(QObject *object)
+bool QDeclarativeVME::initDeferred(QObject *object)
{
QDeclarativeData *data = QDeclarativeData::get(object);
if (!data || !data->context || !data->deferredComponent)
- return;
+ return false;
QDeclarativeContextData *ctxt = data->context;
QDeclarativeCompiledData *comp = data->deferredComponent;
int start = data->deferredIdx;
- QDeclarativeVMEObjectStack stack;
- stack.push(object);
- run(stack, ctxt, comp, start, QBitField());
+ State initState;
+ initState.context = ctxt;
+ initState.compiledData = comp;
+ initState.instructionStream = comp->bytecode.constData() + start;
+ states.push(initState);
+
+ typedef QDeclarativeInstruction I;
+ I *i = (I *)initState.instructionStream;
+
+ Q_ASSERT(comp->instructionType(i) == I::DeferInit);
+
+ objects.allocate(i->deferInit.objectStackSize);
+ lists.allocate(i->deferInit.listStackSize);
+ bindValues.allocate(i->deferInit.bindingsSize);
+ parserStatus.allocate(i->deferInit.parserStatusSize);
+
+ objects.push(object);
+
+ rootContext = 0;
+ engine = ctxt->engine;
+ bindValuesCount = 0;
+ parserStatusCount = 0;
+
+ return true;
+}
+
+namespace {
+struct ActiveVMERestorer
+{
+ ActiveVMERestorer(QDeclarativeVME *me, QDeclarativeEnginePrivate *ep)
+ : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; }
+ ~ActiveVMERestorer() { ep->activeVME = oldVME; }
+
+ QDeclarativeEnginePrivate *ep;
+ QDeclarativeVME *oldVME;
+};
+}
+
+QObject *QDeclarativeVME::execute(QList<QDeclarativeError> *errors, const Interrupt &interrupt)
+{
+ Q_ASSERT(states.count() >= 1);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(states.at(0).context->engine);
+
+ ActiveVMERestorer restore(this, ep);
+
+ QObject *rv = run(errors, interrupt);
+
+ return rv;
}
inline bool fastHasBinding(QObject *o, int index)
@@ -166,9 +196,12 @@ static void removeBindingOnProperty(QObject *o, int index)
if (binding) binding->destroy();
}
+// XXX we probably need some form of "work count" here to prevent us checking this
+// for every instruction.
#define QML_BEGIN_INSTR_COMMON(I) { \
+ if (interrupt.shouldInterrupt()) return 0; \
const QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::DataType &instr = QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::data(*genericInstr); \
- instructionStream += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \
+ INSTRUCTIONSTREAM += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \
Q_UNUSED(instr);
#ifdef QML_THREADED_VME_INTERPRETER
@@ -176,12 +209,12 @@ static void removeBindingOnProperty(QObject *o, int index)
QML_BEGIN_INSTR_COMMON(I)
# define QML_NEXT_INSTR(I) { \
- genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(instructionStream); \
+ genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM); \
goto *genericInstr->common.code; \
}
# define QML_END_INSTR(I) } \
- genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(instructionStream); \
+ genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM); \
goto *genericInstr->common.code;
#else
@@ -195,10 +228,8 @@ static void removeBindingOnProperty(QObject *o, int index)
#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index)
-QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
- QDeclarativeContextData *ctxt,
- QDeclarativeCompiledData *comp,
- int start, const QBitField &bindingSkipList
+QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
+ const Interrupt &interrupt
#ifdef QML_THREADED_VME_INTERPRETER
, void ***storeJumpTable
#endif
@@ -215,121 +246,180 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
return 0;
}
#endif
- Q_ASSERT(comp);
- Q_ASSERT(ctxt);
- const QList<QDeclarativeCompiledData::TypeReference> &types = comp->types;
- const QList<QString> &primitives = comp->primitives;
- const QList<QByteArray> &datas = comp->datas;
- const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches;
- const QList<QDeclarativeScriptData *> &scripts = comp->scripts;
- const QList<QUrl> &urls = comp->urls;
-
- QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues;
- QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> parserStatus;
-
- QDeclarativeVMEStack<ListInstance> qliststack;
+ Q_ASSERT(errors->isEmpty());
+ Q_ASSERT(states.count() >= 1);
- vmeErrors.clear();
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+ QDeclarativeEngine *engine = states.at(0).context->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- int status = -1; //for dbus
+ int status = -1; // needed for dbus
QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor |
QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite;
- const char *instructionStream = comp->bytecode.constData() + start;
+#define COMP states.top().compiledData
+#define CTXT states.top().context
+#define INSTRUCTIONSTREAM states.top().instructionStream
+#define BINDINGSKIPLIST states.top().bindingSkipList
+
+#define TYPES COMP->types
+#define PRIMITIVES COMP->primitives
+#define DATAS COMP->datas
+#define PROPERTYCACHES COMP->propertyCaches
+#define SCRIPTS COMP->scripts
+#define URLS COMP->urls
#ifdef QML_THREADED_VME_INTERPRETER
- const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(instructionStream);
+ const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM);
goto *genericInstr->common.code;
#else
for (;;) {
- const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(instructionStream);
+ const QDeclarativeInstruction *genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM);
switch (genericInstr->common.instructionType) {
#endif
QML_BEGIN_INSTR(Init)
- if (instr.bindingsSize)
- bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.bindingsSize);
- if (instr.parserStatusSize)
- parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.parserStatusSize);
+ // Ensure that the compiled data has been initialized
+ if (!COMP->isInitialized()) COMP->initialize(engine);
+
+ QDeclarativeContextData *parentCtxt = CTXT;
+ CTXT = new QDeclarativeContextData;
+ CTXT->isInternal = true;
+ CTXT->url = COMP->url;
+ CTXT->imports = COMP->importCache;
+ CTXT->imports->addref();
+ CTXT->setParent(parentCtxt);
if (instr.contextCache != -1)
- ctxt->setIdPropertyData(comp->contextCaches.at(instr.contextCache));
+ CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
if (instr.compiledBinding != -1) {
- const char *v4data = datas.at(instr.compiledBinding).constData();
- ctxt->v4bindings = new QDeclarativeV4Bindings(v4data, ctxt, comp);
+ const char *v4data = DATAS.at(instr.compiledBinding).constData();
+ CTXT->v4bindings = new QDeclarativeV4Bindings(v4data, CTXT, COMP);
+ }
+ if (states.count() == 1) {
+ rootContext = CTXT;
+ rootContext->activeVME = this;
}
QML_END_INSTR(Init)
+ QML_BEGIN_INSTR(DeferInit)
+ QML_END_INSTR(DeferInit)
+
QML_BEGIN_INSTR(Done)
- goto normalExit;
+ states.pop();
+
+ if (states.isEmpty())
+ goto normalExit;
QML_END_INSTR(Done)
- QML_BEGIN_INSTR(CreateObject)
- QBitField bindings;
+ QML_BEGIN_INSTR(CreateQMLObject)
+ const QDeclarativeCompiledData::TypeReference &type = TYPES.at(instr.type);
+ Q_ASSERT(type.component);
+
+ states.push(State());
+
+ State *cState = &states[states.count() - 2];
+ State *nState = &states[states.count() - 1];
+
+ nState->context = cState->context;
+ nState->compiledData = type.component;
+ nState->instructionStream = type.component->bytecode.constData();
+
if (instr.bindingBits != -1) {
- const QByteArray &bits = datas.at(instr.bindingBits);
- bindings = QBitField((const quint32*)bits.constData(),
- bits.size() * 8);
+ const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits);
+ nState->bindingSkipList = QBitField((const quint32*)bits.constData(),
+ bits.size() * 8);
}
- if (stack.isEmpty())
- bindings = bindings.united(bindingSkipList);
+ if (instr.isRoot)
+ nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList);
- QObject *o =
- types.at(instr.type).createInstance(ctxt, bindings, &vmeErrors);
+ // As the state in the state stack changed, execution will continue in the new program.
+ QML_END_INSTR(CreateQMLObject)
- if (!o) {
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(types.at(instr.type).className), instr.line);
- }
+ QML_BEGIN_INSTR(CompleteQMLObject)
+ QObject *o = objects.top();
QDeclarativeData *ddata = QDeclarativeData::get(o);
Q_ASSERT(ddata);
- if (stack.isEmpty()) {
+ if (instr.isRoot) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != CTXT);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != CTXT);
+ QDeclarativeContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = CTXT;
+ } else {
+ CTXT->addObject(o);
+ }
+
+ ddata->ownContext = true;
+ } else if (!ddata->context) {
+ CTXT->addObject(o);
+ }
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = CTXT;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
+ QML_END_INSTR(CompleteQMLObject)
+
+ QML_BEGIN_INSTR(CreateCppObject)
+ const QDeclarativeCompiledData::TypeReference &type = TYPES.at(instr.type);
+ Q_ASSERT(type.type);
+
+ QObject *o = 0;
+ void *memory = 0;
+ type.type->create(&o, &memory, sizeof(QDeclarativeData));
+ QDeclarativeData *ddata = new (memory) QDeclarativeData;
+ ddata->ownMemory = false;
+ QObjectPrivate::get(o)->declarativeData = ddata;
+
+ if (type.typePropertyCache && !ddata->propertyCache) {
+ ddata->propertyCache = type.typePropertyCache;
+ ddata->propertyCache->addref();
+ }
+
+ if (!o)
+ VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.className), instr.line);
+
+ if (instr.isRoot) {
if (ddata->context) {
- Q_ASSERT(ddata->context != ctxt);
+ Q_ASSERT(ddata->context != CTXT);
Q_ASSERT(ddata->outerContext);
- Q_ASSERT(ddata->outerContext != ctxt);
+ Q_ASSERT(ddata->outerContext != CTXT);
QDeclarativeContextData *c = ddata->context;
while (c->linkedContext) c = c->linkedContext;
- c->linkedContext = ctxt;
+ c->linkedContext = CTXT;
} else {
- ctxt->addObject(o);
+ CTXT->addObject(o);
}
ddata->ownContext = true;
} else if (!ddata->context) {
- ctxt->addObject(o);
+ CTXT->addObject(o);
}
ddata->setImplicitDestructible();
- ddata->outerContext = ctxt;
+ ddata->outerContext = CTXT;
ddata->lineNumber = instr.line;
ddata->columnNumber = instr.column;
if (instr.data != -1) {
QDeclarativeCustomParser *customParser =
- types.at(instr.type).type->customParser();
- customParser->setCustomData(o, datas.at(instr.data));
+ TYPES.at(instr.type).type->customParser();
+ customParser->setCustomData(o, DATAS.at(instr.data));
}
- if (!stack.isEmpty()) {
- QObject *parent = stack.top();
+ if (!objects.isEmpty()) {
+ QObject *parent = objects.top();
#if 0 // ### refactor
- if (o->isWidgetType()) {
- QWidget *widget = static_cast<QWidget*>(o);
- if (parent->isWidgetType()) {
- QWidget *parentWidget = static_cast<QWidget*>(parent);
- widget->setParent(parentWidget);
- } else {
- // TODO: parent might be a layout
- }
- } else
+ if (o->isWidgetType() && parent->isWidgetType())
+ static_cast<QWidget*>(o)->setParent(static_cast<QWidget*>(parent));
+ else
#endif
- {
QDeclarative_setParent_noEvent(o, parent);
- }
}
- stack.push(o);
- QML_END_INSTR(CreateObject)
+ objects.push(o);
+ QML_END_INSTR(CreateCppObject)
QML_BEGIN_INSTR(CreateSimpleObject)
QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QDeclarativeData));
@@ -337,7 +427,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
instr.create(o);
QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.typeSize);
- const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.type);
+ const QDeclarativeCompiledData::TypeReference &ref = TYPES.at(instr.type);
if (!ddata->propertyCache && ref.typePropertyCache) {
ddata->propertyCache = ref.typePropertyCache;
ddata->propertyCache->addref();
@@ -346,87 +436,85 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
ddata->columnNumber = instr.column;
QObjectPrivate::get(o)->declarativeData = ddata;
- ddata->context = ddata->outerContext = ctxt;
- ddata->nextContextObject = ctxt->contextObjects;
+ ddata->context = ddata->outerContext = CTXT;
+ ddata->nextContextObject = CTXT->contextObjects;
if (ddata->nextContextObject)
ddata->nextContextObject->prevContextObject = &ddata->nextContextObject;
- ddata->prevContextObject = &ctxt->contextObjects;
- ctxt->contextObjects = ddata;
+ ddata->prevContextObject = &CTXT->contextObjects;
+ CTXT->contextObjects = ddata;
- QObject *parent = stack.top();
+ QObject *parent = objects.top();
QDeclarative_setParent_noEvent(o, parent);
- stack.push(o);
+ objects.push(o);
QML_END_INSTR(CreateSimpleObject)
QML_BEGIN_INSTR(SetId)
- QObject *target = stack.top();
- ctxt->setIdProperty(instr.index, target);
+ QObject *target = objects.top();
+ CTXT->setIdProperty(instr.index, target);
QML_END_INSTR(SetId)
QML_BEGIN_INSTR(SetDefault)
- ctxt->contextObject = stack.top();
+ CTXT->contextObject = objects.top();
QML_END_INSTR(SetDefault)
QML_BEGIN_INSTR(CreateComponent)
QDeclarativeComponent *qcomp =
- new QDeclarativeComponent(ctxt->engine, comp, instructionStream - comp->bytecode.constData(),
- stack.isEmpty() ? 0 : stack.top());
+ new QDeclarativeComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(),
+ objects.isEmpty() ? 0 : objects.top());
QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true);
Q_ASSERT(ddata);
- ctxt->addObject(qcomp);
+ CTXT->addObject(qcomp);
- if (stack.isEmpty())
+ if (instr.isRoot)
ddata->ownContext = true;
ddata->setImplicitDestructible();
- ddata->outerContext = ctxt;
+ ddata->outerContext = CTXT;
ddata->lineNumber = instr.line;
ddata->columnNumber = instr.column;
- QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt;
+ QDeclarativeComponentPrivate::get(qcomp)->creationContext = CTXT;
- stack.push(qcomp);
- instructionStream += instr.count;
+ objects.push(qcomp);
+ INSTRUCTIONSTREAM += instr.count;
QML_END_INSTR(CreateComponent)
QML_BEGIN_INSTR(StoreMetaObject)
- QObject *target = stack.top();
+ QObject *target = objects.top();
QMetaObject mo;
- const QByteArray &metadata = datas.at(instr.data);
+ const QByteArray &metadata = DATAS.at(instr.data);
QFastMetaBuilder::fromData(&mo, 0, metadata);
-// QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata);
-
const QDeclarativeVMEMetaData *data =
- (const QDeclarativeVMEMetaData *)datas.at(instr.aliasData).constData();
+ (const QDeclarativeVMEMetaData *)DATAS.at(instr.aliasData).constData();
- (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp);
+ (void)new QDeclarativeVMEMetaObject(target, &mo, data, COMP);
if (instr.propertyCache != -1) {
QDeclarativeData *ddata = QDeclarativeData::get(target, true);
if (ddata->propertyCache) ddata->propertyCache->release();
- ddata->propertyCache = propertyCaches.at(instr.propertyCache);
+ ddata->propertyCache = PROPERTYCACHES.at(instr.propertyCache);
ddata->propertyCache->addref();
}
QML_END_INSTR(StoreMetaObject)
QML_BEGIN_INSTR(StoreVariant)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
// XXX - can be more efficient
- QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.value));
+ QVariant v = QDeclarativeStringConverters::variantFromString(PRIMITIVES.at(instr.value));
void *a[] = { &v, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreVariant)
QML_BEGIN_INSTR(StoreVariantInteger)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVariant v(instr.value);
@@ -436,7 +524,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVariantInteger)
QML_BEGIN_INSTR(StoreVariantDouble)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVariant v(instr.value);
@@ -446,7 +534,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVariantDouble)
QML_BEGIN_INSTR(StoreVariantBool)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVariant v(instr.value);
@@ -456,32 +544,32 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVariantBool)
QML_BEGIN_INSTR(StoreString)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
- void *a[] = { (void *)&primitives.at(instr.value), 0, &status, &flags };
+ void *a[] = { (void *)&PRIMITIVES.at(instr.value), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreString)
QML_BEGIN_INSTR(StoreByteArray)
- QObject *target = stack.top();
- void *a[] = { (void *)&datas.at(instr.value), 0, &status, &flags };
+ QObject *target = objects.top();
+ void *a[] = { (void *)&DATAS.at(instr.value), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreByteArray)
QML_BEGIN_INSTR(StoreUrl)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
- void *a[] = { (void *)&urls.at(instr.value), 0, &status, &flags };
+ void *a[] = { (void *)&URLS.at(instr.value), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.propertyIndex, a);
QML_END_INSTR(StoreUrl)
QML_BEGIN_INSTR(StoreFloat)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
float f = instr.value;
@@ -491,7 +579,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreFloat)
QML_BEGIN_INSTR(StoreDouble)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
double d = instr.value;
@@ -501,7 +589,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreDouble)
QML_BEGIN_INSTR(StoreBool)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
void *a[] = { (void *)&instr.value, 0, &status, &flags };
@@ -510,7 +598,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreBool)
QML_BEGIN_INSTR(StoreInteger)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
void *a[] = { (void *)&instr.value, 0, &status, &flags };
@@ -519,7 +607,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreInteger)
QML_BEGIN_INSTR(StoreColor)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QColor c = QColor::fromRgba(instr.value);
@@ -529,7 +617,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreColor)
QML_BEGIN_INSTR(StoreDate)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QDate d = QDate::fromJulianDay(instr.value);
@@ -539,7 +627,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreDate)
QML_BEGIN_INSTR(StoreTime)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QTime *t = (QTime *)&instr.time;
@@ -549,7 +637,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreTime)
QML_BEGIN_INSTR(StoreDateTime)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QTime *t = (QTime *)&instr.time;
@@ -560,7 +648,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreDateTime)
QML_BEGIN_INSTR(StorePoint)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QPoint *p = (QPoint *)&instr.point;
@@ -570,7 +658,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StorePoint)
QML_BEGIN_INSTR(StorePointF)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QPointF *p = (QPointF *)&instr.point;
@@ -580,7 +668,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StorePointF)
QML_BEGIN_INSTR(StoreSize)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QSize *s = (QSize *)&instr.size;
@@ -590,7 +678,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreSize)
QML_BEGIN_INSTR(StoreSizeF)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QSizeF *s = (QSizeF *)&instr.size;
@@ -600,7 +688,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreSizeF)
QML_BEGIN_INSTR(StoreRect)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QRect *r = (QRect *)&instr.rect;
@@ -610,7 +698,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreRect)
QML_BEGIN_INSTR(StoreRectF)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QRectF *r = (QRectF *)&instr.rect;
@@ -620,7 +708,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreRectF)
QML_BEGIN_INSTR(StoreVector3D)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVector3D *v = (QVector3D *)&instr.vector;
@@ -630,7 +718,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVector3D)
QML_BEGIN_INSTR(StoreVector4D)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVector4D *v = (QVector4D *)&instr.vector;
@@ -640,8 +728,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVector4D)
QML_BEGIN_INSTR(StoreObject)
- QObject *assignObj = stack.pop();
- QObject *target = stack.top();
+ QObject *assignObj = objects.pop();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
void *a[] = { (void *)&assignObj, 0, &status, &flags };
@@ -650,10 +738,10 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreObject)
QML_BEGIN_INSTR(AssignCustomType)
- QObject *target = stack.top();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
- const QString &primitive = primitives.at(instr.primitive);
+ const QString &primitive = PRIMITIVES.at(instr.primitive);
int type = instr.type;
QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
QVariant v = (*converter)(primitive);
@@ -661,7 +749,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QMetaProperty prop =
target->metaObject()->property(instr.propertyIndex);
if (v.isNull() || ((int)prop.type() != type && prop.userType() != type))
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
+ VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
void *a[] = { (void *)v.data(), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -671,55 +759,55 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_BEGIN_INSTR(AssignSignalObject)
// XXX optimize
- QObject *assign = stack.pop();
- QObject *target = stack.top();
+ QObject *assign = objects.pop();
+ QObject *target = objects.top();
int sigIdx = instr.signal;
- const QString &pr = primitives.at(sigIdx);
+ const QString &pr = PRIMITIVES.at(sigIdx);
QDeclarativeProperty prop(target, pr);
if (prop.type() & QDeclarativeProperty::SignalProperty) {
QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign);
if (method.signature() == 0)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
+ VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature()))
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line);
+ VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line);
QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
} else {
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(pr), instr.line);
+ VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line);
}
QML_END_INSTR(AssignSignalObject)
QML_BEGIN_INSTR(StoreSignal)
- QObject *target = stack.top();
- QObject *context = stack.at(stack.count() - 1 - instr.context);
+ QObject *target = objects.top();
+ QObject *context = objects.at(objects.count() - 1 - instr.context);
QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
QDeclarativeExpression *expr =
- new QDeclarativeExpression(ctxt, context, primitives.at(instr.value));
- expr->setSourceLocation(comp->name, instr.line);
- static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.name);
+ new QDeclarativeExpression(CTXT, context, PRIMITIVES.at(instr.value));
+ expr->setSourceLocation(COMP->name, instr.line);
+ static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = DATAS.at(instr.name);
bs->setExpression(expr);
QML_END_INSTR(StoreSignal)
QML_BEGIN_INSTR(StoreImportedScript)
- ctxt->importedScripts << run(ctxt, scripts.at(instr.value));
+ CTXT->importedScripts << run(CTXT, SCRIPTS.at(instr.value));
QML_END_INSTR(StoreImportedScript)
QML_BEGIN_INSTR(StoreScriptString)
- QObject *target = stack.top();
- QObject *scope = stack.at(stack.count() - 1 - instr.scope);
+ QObject *target = objects.top();
+ QObject *scope = objects.at(objects.count() - 1 - instr.scope);
QDeclarativeScriptString ss;
- ss.setContext(ctxt->asQDeclarativeContext());
+ ss.setContext(CTXT->asQDeclarativeContext());
ss.setScopeObject(scope);
- ss.setScript(primitives.at(instr.value));
+ ss.setScript(PRIMITIVES.at(instr.value));
ss.d.data()->bindingId = instr.bindingId;
ss.d.data()->lineNumber = instr.line;
@@ -729,37 +817,37 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreScriptString)
QML_BEGIN_INSTR(BeginObject)
- QObject *target = stack.top();
+ QObject *target = objects.top();
QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
- parserStatus.append(status);
- status->d = &parserStatus.values[parserStatus.count - 1];
+ parserStatus.push(status);
+ status->d = &parserStatus.top();
status->classBegin();
QML_END_INSTR(BeginObject)
QML_BEGIN_INSTR(InitV8Bindings)
- ctxt->v8bindings = new QV8Bindings(primitives.at(instr.program), instr.programIndex,
- instr.line, comp, ctxt);
+ CTXT->v8bindings = new QV8Bindings(PRIMITIVES.at(instr.program), instr.programIndex,
+ instr.line, COMP, CTXT);
QML_END_INSTR(InitV8Bindings)
QML_BEGIN_INSTR(StoreBinding)
QObject *target =
- stack.at(stack.count() - 1 - instr.owner);
+ objects.at(objects.count() - 1 - instr.owner);
QObject *context =
- stack.at(stack.count() - 1 - instr.context);
+ objects.at(objects.count() - 1 - instr.context);
QDeclarativeProperty mp =
- QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ QDeclarativePropertyPrivate::restore(DATAS.at(instr.property), target, CTXT);
int coreIndex = mp.index();
- if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(coreIndex))
QML_NEXT_INSTR(StoreBinding);
- QDeclarativeBinding *bind = new QDeclarativeBinding(primitives.at(instr.value), true,
- context, ctxt, comp->name, instr.line);
- bindValues.append(bind);
- bind->m_mePtr = &bindValues.values[bindValues.count - 1];
+ QDeclarativeBinding *bind = new QDeclarativeBinding(PRIMITIVES.at(instr.value), true,
+ context, CTXT, COMP->name, instr.line);
+ bindValues.push(bind);
+ bind->m_mePtr = &bindValues.top();
bind->setTarget(mp);
bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp));
@@ -767,22 +855,22 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_BEGIN_INSTR(StoreBindingOnAlias)
QObject *target =
- stack.at(stack.count() - 1 - instr.owner);
+ objects.at(objects.count() - 1 - instr.owner);
QObject *context =
- stack.at(stack.count() - 1 - instr.context);
+ objects.at(objects.count() - 1 - instr.context);
QDeclarativeProperty mp =
- QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ QDeclarativePropertyPrivate::restore(DATAS.at(instr.property), target, CTXT);
int coreIndex = mp.index();
- if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(coreIndex))
QML_NEXT_INSTR(StoreBindingOnAlias);
- QDeclarativeBinding *bind = new QDeclarativeBinding(primitives.at(instr.value), true,
- context, ctxt, comp->name, instr.line);
- bindValues.append(bind);
- bind->m_mePtr = &bindValues.values[bindValues.count - 1];
+ QDeclarativeBinding *bind = new QDeclarativeBinding(PRIMITIVES.at(instr.value), true,
+ context, CTXT, COMP->name, instr.line);
+ bindValues.push(bind);
+ bind->m_mePtr = &bindValues.top();
bind->setTarget(mp);
QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind);
@@ -791,59 +879,59 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_BEGIN_INSTR(StoreV4Binding)
QObject *target =
- stack.at(stack.count() - 1 - instr.owner);
+ objects.at(objects.count() - 1 - instr.owner);
QObject *scope =
- stack.at(stack.count() - 1 - instr.context);
+ objects.at(objects.count() - 1 - instr.context);
int property = instr.property;
- if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF))
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(property & 0xFFFF))
QML_NEXT_INSTR(StoreV4Binding);
QDeclarativeAbstractBinding *binding =
- ctxt->v4bindings->configBinding(instr.value, target, scope, property);
- bindValues.append(binding);
- binding->m_mePtr = &bindValues.values[bindValues.count - 1];
+ CTXT->v4bindings->configBinding(instr.value, target, scope, property);
+ bindValues.push(binding);
+ binding->m_mePtr = &bindValues.top();
binding->addToObject(target, property);
QML_END_INSTR(StoreV4Binding)
QML_BEGIN_INSTR(StoreV8Binding)
QObject *target =
- stack.at(stack.count() - 1 - instr.owner);
+ objects.at(objects.count() - 1 - instr.owner);
QObject *scope =
- stack.at(stack.count() - 1 - instr.context);
+ objects.at(objects.count() - 1 - instr.context);
QDeclarativeProperty mp =
- QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ QDeclarativePropertyPrivate::restore(DATAS.at(instr.property), target, CTXT);
int coreIndex = mp.index();
- if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(coreIndex))
QML_NEXT_INSTR(StoreV8Binding);
QDeclarativeAbstractBinding *binding =
- ctxt->v8bindings->configBinding(instr.value, target, scope, mp, instr.line);
- bindValues.append(binding);
- binding->m_mePtr = &bindValues.values[bindValues.count - 1];
+ CTXT->v8bindings->configBinding(instr.value, target, scope, mp, instr.line);
+ bindValues.push(binding);
+ binding->m_mePtr = &bindValues.top();
binding->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp));
QML_END_INSTR(StoreV8Binding)
QML_BEGIN_INSTR(StoreValueSource)
- QObject *obj = stack.pop();
+ QObject *obj = objects.pop();
QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
- QObject *target = stack.at(stack.count() - 1 - instr.owner);
+ QObject *target = objects.at(objects.count() - 1 - instr.owner);
QDeclarativeProperty prop =
- QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ QDeclarativePropertyPrivate::restore(DATAS.at(instr.property), target, CTXT);
obj->setParent(target);
vs->setTarget(prop);
QML_END_INSTR(StoreValueSource)
QML_BEGIN_INSTR(StoreValueInterceptor)
- QObject *obj = stack.pop();
+ QObject *obj = objects.pop();
QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
- QObject *target = stack.at(stack.count() - 1 - instr.owner);
+ QObject *target = objects.at(objects.count() - 1 - instr.owner);
QDeclarativeProperty prop =
- QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ QDeclarativePropertyPrivate::restore(DATAS.at(instr.property), target, CTXT);
obj->setParent(target);
vi->setTarget(prop);
QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject());
@@ -851,16 +939,16 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreValueInterceptor)
QML_BEGIN_INSTR(StoreObjectQList)
- QObject *assign = stack.pop();
+ QObject *assign = objects.pop();
- const ListInstance &list = qliststack.top();
+ const List &list = lists.top();
list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign);
QML_END_INSTR(StoreObjectQList)
QML_BEGIN_INSTR(AssignObjectList)
// This is only used for assigning interfaces
- QObject *assign = stack.pop();
- const ListInstance &list = qliststack.top();
+ QObject *assign = objects.pop();
+ const List &list = lists.top();
int type = list.type;
@@ -870,15 +958,15 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
if (iid)
ptr = assign->qt_metacast(iid);
if (!ptr)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list"), instr.line);
+ VME_EXCEPTION(tr("Cannot assign object to list"), instr.line);
list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr);
QML_END_INSTR(AssignObjectList)
QML_BEGIN_INSTR(StoreVariantObject)
- QObject *assign = stack.pop();
- QObject *target = stack.top();
+ QObject *assign = objects.pop();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
QVariant v = QVariant::fromValue(assign);
@@ -888,8 +976,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QML_END_INSTR(StoreVariantObject)
QML_BEGIN_INSTR(StoreInterface)
- QObject *assign = stack.pop();
- QObject *target = stack.top();
+ QObject *assign = objects.pop();
+ QObject *target = objects.top();
CLEAN_PROPERTY(target, instr.propertyIndex);
int coreIdx = instr.propertyIndex;
@@ -909,33 +997,33 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
}
if (!ok)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property"), instr.line);
+ VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line);
QML_END_INSTR(StoreInterface)
QML_BEGIN_INSTR(FetchAttached)
- QObject *target = stack.top();
+ QObject *target = objects.top();
QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
if (!qmlObject)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object"), instr.line);
+ VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
- stack.push(qmlObject);
+ objects.push(qmlObject);
QML_END_INSTR(FetchAttached)
QML_BEGIN_INSTR(FetchQList)
- QObject *target = stack.top();
+ QObject *target = objects.top();
- qliststack.push(ListInstance(instr.type));
+ lists.push(List(instr.type));
void *a[1];
- a[0] = (void *)&(qliststack.top().qListProperty);
+ a[0] = (void *)&(lists.top().qListProperty);
QMetaObject::metacall(target, QMetaObject::ReadProperty,
instr.property, a);
QML_END_INSTR(FetchQList)
QML_BEGIN_INSTR(FetchObject)
- QObject *target = stack.top();
+ QObject *target = objects.top();
QObject *obj = 0;
// NOTE: This assumes a cast to QObject does not alter the
@@ -946,33 +1034,33 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
instr.property, a);
if (!obj)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
+ VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
- stack.push(obj);
+ objects.push(obj);
QML_END_INSTR(FetchObject)
QML_BEGIN_INSTR(PopQList)
- qliststack.pop();
+ lists.pop();
QML_END_INSTR(PopQList)
QML_BEGIN_INSTR(Defer)
if (instr.deferCount) {
- QObject *target = stack.top();
+ QObject *target = objects.top();
QDeclarativeData *data =
QDeclarativeData::get(target, true);
- comp->addref();
- data->deferredComponent = comp;
- data->deferredIdx = instructionStream - comp->bytecode.constData();
- instructionStream += instr.deferCount;
+ COMP->addref();
+ data->deferredComponent = COMP;
+ data->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData();
+ INSTRUCTIONSTREAM += instr.deferCount;
}
QML_END_INSTR(Defer)
QML_BEGIN_INSTR(PopFetchedObject)
- stack.pop();
+ objects.pop();
QML_END_INSTR(PopFetchedObject)
QML_BEGIN_INSTR(FetchValueType)
- QObject *target = stack.top();
+ QObject *target = objects.top();
if (instr.bindingSkipList != 0) {
// Possibly need to clear bindings
@@ -994,13 +1082,13 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
QDeclarativeValueType *valueHandler = ep->valueTypes[instr.type];
valueHandler->read(target, instr.property);
- stack.push(valueHandler);
+ objects.push(valueHandler);
QML_END_INSTR(FetchValueType)
QML_BEGIN_INSTR(PopValueType)
QDeclarativeValueType *valueHandler =
- static_cast<QDeclarativeValueType *>(stack.pop());
- QObject *target = stack.top();
+ static_cast<QDeclarativeValueType *>(objects.pop());
+ QObject *target = objects.top();
valueHandler->write(target, instr.property, QDeclarativePropertyPrivate::BypassInterceptor);
QML_END_INSTR(PopValueType)
@@ -1014,67 +1102,56 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack,
}
#endif
- exceptionExit:
- Q_ASSERT(isError());
- if (!stack.isEmpty()) {
- delete stack.at(0); // ### What about failures in deferred creation?
- } else {
- ctxt->destroy();
- }
+exceptionExit:
+ if (!objects.isEmpty())
+ delete objects.at(0); // XXX What about failures in deferred creation?
+
+ // XXX does context get leaked in this case?
+
+ Q_ASSERT(!errors->isEmpty());
+
+ // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
+ blank(parserStatus);
+ blank(bindValues);
+
+ objects.deallocate();
+ lists.deallocate();
+ states.clear();
+ bindValues.deallocate();
+ parserStatus.deallocate();
+ finalizeCallbacks.clear();
- QDeclarativeEnginePrivate::clear(bindValues);
- QDeclarativeEnginePrivate::clear(parserStatus);
return 0;
- normalExit:
- if (bindValues.count)
- ep->bindValues << bindValues;
- else if (bindValues.values)
- bindValues.clear();
+normalExit:
+ Q_ASSERT(objects.count() == 1);
- if (parserStatus.count)
- ep->parserStatus << parserStatus;
- else if (parserStatus.values)
- parserStatus.clear();
+ QObject *rv = objects.top();
- Q_ASSERT(stack.count() == 1);
- return stack.top();
-}
+ objects.deallocate();
+ lists.deallocate();
+ states.clear();
-bool QDeclarativeVME::isError() const
-{
- return !vmeErrors.isEmpty();
+ return rv;
}
-QList<QDeclarativeError> QDeclarativeVME::errors() const
+// Must be called with a handle scope and context
+void QDeclarativeScriptData::initialize(QDeclarativeEngine *engine)
{
- return vmeErrors;
-}
+ Q_ASSERT(m_program.IsEmpty());
+ Q_ASSERT(engine);
+ Q_ASSERT(!hasEngine());
-QObject *
-QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData *ctxt,
- const QBitField &bindings,
- QList<QDeclarativeError> *errors) const
-{
- if (type) {
- QObject *rv = 0;
- void *memory = 0;
-
- type->create(&rv, &memory, sizeof(QDeclarativeData));
- QDeclarativeData *ddata = new (memory) QDeclarativeData;
- ddata->ownMemory = false;
- QObjectPrivate::get(rv)->declarativeData = ddata;
-
- if (typePropertyCache && !ddata->propertyCache) {
- ddata->propertyCache = typePropertyCache;
- ddata->propertyCache->addref();
- }
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QV8Engine *v8engine = ep->v8engine();
- return rv;
- } else {
- Q_ASSERT(component);
- return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, 0, errors, bindings);
- }
+ // XXX Handle errors during the script compile!
+ v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource, url.toString(), 1);
+ m_program = qPersistentNew<v8::Script>(program);
+
+ addToEngine(engine);
+
+ addref();
}
v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
@@ -1126,6 +1203,9 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC
v8::HandleScope handle_scope;
v8::Context::Scope scope(v8engine->context());
+ if (!script->isInitialized())
+ script->initialize(parentCtxt->engine);
+
v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
v8::TryCatch try_catch;
@@ -1157,55 +1237,91 @@ void **QDeclarativeVME::instructionJumpTable()
static void **jumpTable = 0;
if (!jumpTable) {
QDeclarativeVME dummy;
- QDeclarativeVMEObjectStack stack;
- dummy.run(stack, 0, 0, 0, QBitField(), &jumpTable);
+ QDeclarativeVME::Interrupt i;
+ dummy.run(0, i, &jumpTable);
}
return jumpTable;
}
#endif
-template<typename T>
-QDeclarativeVMEStack<T>::QDeclarativeVMEStack()
-: _index(-1)
+bool QDeclarativeVME::complete(const Interrupt &interrupt)
{
-}
+ ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine));
+
+ while (bindValuesCount < bindValues.count()) {
+ if(bindValues.at(bindValuesCount)) {
+ QDeclarativeAbstractBinding *b = bindValues.at(bindValuesCount);
+ b->m_mePtr = 0;
+ b->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
+ QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ ++bindValuesCount;
-template<typename T>
-bool QDeclarativeVMEStack<T>::isEmpty() const {
- return _index == -1;
-}
+ if (interrupt.shouldInterrupt())
+ return false;
+ }
+ bindValues.deallocate();
-template<typename T>
-const T &QDeclarativeVMEStack<T>::top() const {
- return at(_index);
-}
+ while (parserStatusCount < parserStatus.count()) {
+ QDeclarativeParserStatus *status =
+ parserStatus.at(parserStatus.count() - parserStatusCount - 1);
-template<typename T>
-void QDeclarativeVMEStack<T>::push(const T &o) {
- _index++;
+ if (status && status->d) {
+ status->d = 0;
+ status->componentComplete();
+ }
+
+ ++parserStatusCount;
- Q_ASSERT(_index <= VLA::size());
- if (_index == VLA::size())
- this->append(o);
- else
- VLA::data()[_index] = o;
-}
+ if (interrupt.shouldInterrupt())
+ return false;
+ }
+ parserStatus.deallocate();
+
+ while (componentAttached) {
+ QDeclarativeComponentAttached *a = componentAttached;
+ a->rem();
+ QDeclarativeData *d = QDeclarativeData::get(a->parent());
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ emit a->completed();
+
+ if (interrupt.shouldInterrupt())
+ return false;
+ }
+
+ // XXX (what if its deleted?)
+ if (rootContext)
+ rootContext->activeVME = 0;
+
+ for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
+ QDeclarativeEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
+ QObject *obj = callback.first;
+ if (obj) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
+ }
+ }
+ finalizeCallbacks.clear();
-template<typename T>
-T QDeclarativeVMEStack<T>::pop() {
- Q_ASSERT(_index >= 0);
- --_index;
- return VLA::data()[_index + 1];
+ return true;
}
-template<typename T>
-int QDeclarativeVMEStack<T>::count() const {
- return _index + 1;
+void QDeclarativeVME::blank(QFiniteStack<QDeclarativeAbstractBinding *> &bs)
+{
+ for (int ii = 0; ii < bs.count(); ++ii) {
+ QDeclarativeAbstractBinding *b = bs.at(ii);
+ if (b) b->m_mePtr = 0;
+ }
}
-template<typename T>
-const T &QDeclarativeVMEStack<T>::at(int index) const {
- return VLA::data()[index];
+void QDeclarativeVME::blank(QFiniteStack<QDeclarativeParserStatus *> &pss)
+{
+ for (int ii = 0; ii < pss.count(); ++ii) {
+ QDeclarativeParserStatus *ps = pss.at(ii);
+ if(ps) ps->d = 0;
+ }
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index a0dae77501..3d79f9d340 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -57,10 +57,14 @@
#include "private/qbitfield_p.h"
#include "private/qdeclarativeinstruction_p.h"
-#include <QtCore/QString>
#include <QtCore/QStack>
+#include <QtCore/QString>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qcoreapplication.h>
#include <private/qv8_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qfinitestack_p.h>
QT_BEGIN_NAMESPACE
@@ -70,39 +74,127 @@ class QDeclarativeScriptData;
class QDeclarativeCompiledData;
class QDeclarativeCompiledData;
class QDeclarativeContextData;
-class QDeclarativeVMEObjectStack;
+
+namespace QDeclarativeVMETypes {
+ struct List
+ {
+ List() : type(0) {}
+ List(int t) : type(t) {}
+
+ int type;
+ QDeclarativeListProperty<void> qListProperty;
+ };
+}
+Q_DECLARE_TYPEINFO(QDeclarativeVMETypes::List, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
class QDeclarativeVME
{
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativeVME)
public:
- QDeclarativeVME();
-
- QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
- int start = -1, const QBitField & = QBitField());
-
- void runDeferred(QObject *);
-
- bool isError() const;
- QList<QDeclarativeError> errors() const;
+ class Interrupt {
+ public:
+ inline Interrupt();
+ inline Interrupt(bool *runWhile);
+ inline Interrupt(int nsecs);
+
+ inline void reset();
+ inline bool shouldInterrupt() const;
+ private:
+ enum Mode { None, Time, Flag };
+ Mode mode;
+ union {
+ struct {
+ QElapsedTimer timer;
+ int nsecs;
+ };
+ bool *runWhile;
+ };
+ };
+
+ QDeclarativeVME() : data(0), componentAttached(0) {}
+ QDeclarativeVME(void *data) : data(data), componentAttached(0) {}
+
+ void *data;
+ QDeclarativeComponentAttached *componentAttached;
+ QList<QDeclarativeEnginePrivate::FinalizeCallback> finalizeCallbacks;
+
+ void init(QDeclarativeContextData *, QDeclarativeCompiledData *, int start);
+ bool initDeferred(QObject *);
+
+ QObject *execute(QList<QDeclarativeError> *errors, const Interrupt & = Interrupt());
+ bool complete(const Interrupt & = Interrupt());
private:
- v8::Persistent<v8::Object> run(QDeclarativeContextData *, QDeclarativeScriptData *);
-
- QObject *run(QDeclarativeVMEObjectStack &,
- QDeclarativeContextData *, QDeclarativeCompiledData *,
- int start, const QBitField &
+ QObject *run(QList<QDeclarativeError> *errors, const Interrupt &
#ifdef QML_THREADED_VME_INTERPRETER
, void ***storeJumpTable = 0
#endif
- );
- QList<QDeclarativeError> vmeErrors;
+ );
+ v8::Persistent<v8::Object> run(QDeclarativeContextData *, QDeclarativeScriptData *);
#ifdef QML_THREADED_VME_INTERPRETER
static void **instructionJumpTable();
friend class QDeclarativeCompiledData;
#endif
+
+ QDeclarativeEngine *engine;
+ QFiniteStack<QObject *> objects;
+ QFiniteStack<QDeclarativeVMETypes::List> lists;
+
+ int bindValuesCount;
+ int parserStatusCount;
+ QFiniteStack<QDeclarativeAbstractBinding *> bindValues;
+ QFiniteStack<QDeclarativeParserStatus *> parserStatus;
+ QDeclarativeContextData *rootContext;
+
+ struct State {
+ State() : context(0), compiledData(0), instructionStream(0) {}
+ QDeclarativeContextData *context;
+ QDeclarativeCompiledData *compiledData;
+ const char *instructionStream;
+ QBitField bindingSkipList;
+ };
+
+ QStack<State> states;
+
+ static void blank(QFiniteStack<QDeclarativeParserStatus *> &);
+ static void blank(QFiniteStack<QDeclarativeAbstractBinding *> &);
};
+QDeclarativeVME::Interrupt::Interrupt()
+: mode(None)
+{
+}
+
+QDeclarativeVME::Interrupt::Interrupt(bool *runWhile)
+: mode(Flag), runWhile(runWhile)
+{
+}
+
+QDeclarativeVME::Interrupt::Interrupt(int nsecs)
+: mode(Time), nsecs(nsecs)
+{
+}
+
+void QDeclarativeVME::Interrupt::reset()
+{
+ if (mode == Time)
+ timer.start();
+}
+
+bool QDeclarativeVME::Interrupt::shouldInterrupt() const
+{
+ if (mode == None) {
+ return false;
+ } else if (mode == Time) {
+ return timer.nsecsElapsed() > nsecs;
+ } else if (mode == Flag) {
+ return !*runWhile;
+ } else {
+ return false;
+ }
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEVME_P_H
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index 61e3aa3ab9..608b212915 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -7,6 +7,7 @@ SOURCES += \
$$PWD/qdeclarativebinding.cpp \
$$PWD/qdeclarativeproperty.cpp \
$$PWD/qdeclarativecomponent.cpp \
+ $$PWD/qdeclarativeincubator.cpp \
$$PWD/qdeclarativecontext.cpp \
$$PWD/qdeclarativecustomparser.cpp \
$$PWD/qdeclarativepropertyvaluesource.cpp \
@@ -54,6 +55,8 @@ HEADERS += \
$$PWD/qdeclarativeproperty.h \
$$PWD/qdeclarativecomponent.h \
$$PWD/qdeclarativecomponent_p.h \
+ $$PWD/qdeclarativeincubator.h \
+ $$PWD/qdeclarativeincubator_p.h \
$$PWD/qdeclarativecustomparser_p.h \
$$PWD/qdeclarativecustomparser_p_p.h \
$$PWD/qdeclarativepropertyvaluesource.h \
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
index 1a1f5cc8f6..7aa5496403 100644
--- a/src/declarative/qml/v4/qdeclarativev4bindings.cpp
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -749,9 +749,12 @@ void **QDeclarativeV4Bindings::getDecodeInstrTable()
{
static void **decode_instr;
if (!decode_instr) {
- QDeclarativeV4Bindings dummy(0, 0, 0);
+ QDeclarativeV4Bindings *dummy = new QDeclarativeV4Bindings(0, 0, 0);
quint32 executedBlocks = 0;
- dummy.d_func()->run(0, executedBlocks, 0, 0, 0, 0, QDeclarativePropertyPrivate::BypassInterceptor, &decode_instr);
+ dummy->d_func()->run(0, executedBlocks, 0, 0, 0, 0,
+ QDeclarativePropertyPrivate::BypassInterceptor,
+ &decode_instr);
+ dummy->release();
}
return decode_instr;
}
@@ -786,7 +789,6 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
executedBlocks = 0;
- QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
const char *code = program->instructions();
code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h
index 6fa47d8e3d..114584cdc2 100644
--- a/src/declarative/qml/v8/qv8engine_p.h
+++ b/src/declarative/qml/v8/qv8engine_p.h
@@ -135,7 +135,8 @@ public:
QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
- ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, ParticleDataType, SignalHandlerType};
+ ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType,
+ ParticleDataType, SignalHandlerType, IncubatorType };
virtual ResourceType resourceType() const = 0;
QV8Engine *engine;
diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
index 2649976513..9481bb54fe 100644
--- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
@@ -861,6 +861,7 @@ static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *
v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
{
Q_ASSERT(object);
+ Q_ASSERT(this->engine);
Q_ASSERT(QDeclarativeData::get(object, false));
Q_ASSERT(QDeclarativeData::get(object, false)->propertyCache == this);
@@ -938,6 +939,8 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
ft->InstanceTemplate()->SetHasExternalResource(true);
constructor = qPersistentNew<v8::Function>(ft->GetFunction());
}
+
+ QDeclarativeCleanup::addToEngine(this->engine);
}
v8::Local<v8::Object> result = constructor->NewInstance();
diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp
index e642f11fbc..bbb5e33aa2 100644
--- a/src/declarative/util/qdeclarativeanimation.cpp
+++ b/src/declarative/util/qdeclarativeanimation.cpp
@@ -188,7 +188,7 @@ void QDeclarativeAbstractAnimation::setRunning(bool r)
else if (!d->registered) {
d->registered = true;
QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
- engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
}
return;
}
diff --git a/src/declarative/util/qdeclarativebehavior.cpp b/src/declarative/util/qdeclarativebehavior.cpp
index 3038d3a207..71bbc7f2ac 100644
--- a/src/declarative/util/qdeclarativebehavior.cpp
+++ b/src/declarative/util/qdeclarativebehavior.cpp
@@ -220,7 +220,7 @@ void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property)
d->animation->setDefaultTarget(property);
QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
- engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
}
void QDeclarativeBehavior::componentFinalized()
diff --git a/src/qtquick1/util/qdeclarativeanimation.cpp b/src/qtquick1/util/qdeclarativeanimation.cpp
index 8204e33022..cc1ada151a 100644
--- a/src/qtquick1/util/qdeclarativeanimation.cpp
+++ b/src/qtquick1/util/qdeclarativeanimation.cpp
@@ -191,7 +191,7 @@ void QDeclarative1AbstractAnimation::setRunning(bool r)
else if (!d->registered) {
d->registered = true;
QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
- engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
}
return;
}
diff --git a/src/qtquick1/util/qdeclarativebehavior.cpp b/src/qtquick1/util/qdeclarativebehavior.cpp
index 0475eea01f..eb0f5880f1 100644
--- a/src/qtquick1/util/qdeclarativebehavior.cpp
+++ b/src/qtquick1/util/qdeclarativebehavior.cpp
@@ -221,7 +221,7 @@ void QDeclarative1Behavior::setTarget(const QDeclarativeProperty &property)
d->animation->setDefaultTarget(property);
QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
- engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
}
void QDeclarative1Behavior::componentFinalized()
diff --git a/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp b/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp
index 98c5f7d9b0..fa860befbf 100644
--- a/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp
+++ b/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp
@@ -75,7 +75,9 @@ static void msgHandler(QtMsgType, const char *msg)
void tst_qdeclarativeinstruction::dump()
{
- QDeclarativeCompiledData *data = new QDeclarativeCompiledData(0);
+ QDeclarativeEngine engine;
+ QDeclarativeCompiledData *data = new QDeclarativeCompiledData(&engine);
+
{
QDeclarativeCompiledData::Instruction::Init i;
i.bindingsSize = 0;
@@ -90,10 +92,9 @@ void tst_qdeclarativeinstruction::dump()
ref.className = "Test";
data->types << ref;
- QDeclarativeCompiledData::Instruction::CreateObject i;
+ QDeclarativeCompiledData::Instruction::CreateCppObject i;
i.type = 0;
i.data = -1;
- i.bindingBits = -1;
i.column = 10;
data->addInstruction(i);
}
@@ -309,10 +310,10 @@ void tst_qdeclarativeinstruction::dump()
}
{
- data->datas << "mySignal";
+ data->primitives << "mySignal";
QDeclarativeCompiledData::Instruction::AssignSignalObject i;
- i.signal = 0;
+ i.signal = data->primitives.count() - 1;
data->addInstruction(i);
}
@@ -459,7 +460,7 @@ void tst_qdeclarativeinstruction::dump()
<< "Index\tOperation\t\tData1\tData2\tData3\tComments"
<< "-------------------------------------------------------------------------------"
<< "0\t\tINIT\t\t\t0\t3\t-1\t-1"
- << "1\t\tCREATE\t\t\t0\t-1\t\t\"Test\""
+ << "1\t\tCREATECPP\t\t\t0\t\t\t\"Test\""
<< "2\t\tSETID\t\t\t0\t\t\t\"testId\""
<< "3\t\tSET_DEFAULT"
<< "4\t\tCREATE_COMPONENT\t3"
@@ -487,7 +488,7 @@ void tst_qdeclarativeinstruction::dump()
<< "26\t\tSTORE_INTERFACE\t\t23"
<< "27\t\tSTORE_SIGNAL\t\t2\t3\t\t\"console.log(1921)\""
<< "28\t\tSTORE_SCRIPT_STRING\t24\t3\t1\t4"
- << "29\t\tASSIGN_SIGNAL_OBJECT\t0\t\t\t\"mySignal\""
+ << "29\t\tASSIGN_SIGNAL_OBJECT\t4\t\t\t\"mySignal\""
<< "30\t\tASSIGN_CUSTOMTYPE\t25\t6\t9"
<< "31\t\tSTORE_BINDING\t26\t3\t2"
<< "32\t\tSTORE_COMPILED_BINDING\t27\t2\t4"
@@ -513,6 +514,7 @@ void tst_qdeclarativeinstruction::dump()
messages = QStringList();
QtMsgHandler old = qInstallMsgHandler(msgHandler);
+
data->dumpInstructions();
qInstallMsgHandler(old);