Asynchronous component instantiation
authorAaron Kennedy <aaron.kennedy@nokia.com>
Mon, 5 Sep 2011 07:31:41 +0000 (17:31 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 29 Sep 2011 04:12:49 +0000 (06:12 +0200)
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>

46 files changed:
src/declarative/qml/ftw/ftw.pri
src/declarative/qml/ftw/qdeclarativerefcount_p.h
src/declarative/qml/ftw/qdeclarativethread.cpp [new file with mode: 0644]
src/declarative/qml/ftw/qdeclarativethread_p.h [new file with mode: 0644]
src/declarative/qml/ftw/qfieldlist_p.h
src/declarative/qml/ftw/qfinitestack_p.h [new file with mode: 0644]
src/declarative/qml/qdeclarativecleanup.cpp
src/declarative/qml/qdeclarativecleanup_p.h
src/declarative/qml/qdeclarativecompileddata.cpp
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativecompiler_p.h
src/declarative/qml/qdeclarativecomponent.cpp
src/declarative/qml/qdeclarativecomponent.h
src/declarative/qml/qdeclarativecomponent_p.h
src/declarative/qml/qdeclarativecontext.cpp
src/declarative/qml/qdeclarativecontext_p.h
src/declarative/qml/qdeclarativeengine.cpp
src/declarative/qml/qdeclarativeengine.h
src/declarative/qml/qdeclarativeengine_p.h
src/declarative/qml/qdeclarativeextensioninterface.h
src/declarative/qml/qdeclarativeextensionplugin.h
src/declarative/qml/qdeclarativeimport.cpp
src/declarative/qml/qdeclarativeimport_p.h
src/declarative/qml/qdeclarativeincubator.cpp [new file with mode: 0644]
src/declarative/qml/qdeclarativeincubator.h [new file with mode: 0644]
src/declarative/qml/qdeclarativeincubator_p.h [moved from src/declarative/qml/ftw/qdeclarativerefcount.cpp with 58% similarity]
src/declarative/qml/qdeclarativeinstruction.cpp
src/declarative/qml/qdeclarativeinstruction_p.h
src/declarative/qml/qdeclarativepropertycache.cpp
src/declarative/qml/qdeclarativepropertycache_p.h
src/declarative/qml/qdeclarativescript.cpp
src/declarative/qml/qdeclarativetypeloader.cpp
src/declarative/qml/qdeclarativetypeloader_p.h
src/declarative/qml/qdeclarativetypenamecache.cpp
src/declarative/qml/qdeclarativetypenamecache_p.h
src/declarative/qml/qdeclarativevme.cpp
src/declarative/qml/qdeclarativevme_p.h
src/declarative/qml/qml.pri
src/declarative/qml/v4/qdeclarativev4bindings.cpp
src/declarative/qml/v8/qv8engine_p.h
src/declarative/qml/v8/qv8qobjectwrapper.cpp
src/declarative/util/qdeclarativeanimation.cpp
src/declarative/util/qdeclarativebehavior.cpp
src/qtquick1/util/qdeclarativeanimation.cpp
src/qtquick1/util/qdeclarativebehavior.cpp
tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp

index d6e7df5..2d6729b 100644 (file)
@@ -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 \
 
index 3813270..8ae9618 100644 (file)
@@ -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 (file)
index 0000000..4a21c90
--- /dev/null
@@ -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 (file)
index 0000000..2f58155
--- /dev/null
@@ -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
index ff6b89b..f0efd16 100644 (file)
@@ -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 (file)
index 0000000..de9d833
--- /dev/null
@@ -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
+
index db671a3..d0d3687 100644 (file)
@@ -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
index 1efe564..272b0c8 100644 (file)
@@ -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
index a1bdca2..6815967 100644 (file)
@@ -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
index fe0375f..8c26a3b 100644 (file)
@@ -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) {
index a4def99..993c733 100644 (file)
@@ -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
     {
index d5a55fe..50c6471 100644 (file)
@@ -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"
 
 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
index a3457d1..92af689 100644 (file)
@@ -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);
index ba93749..7e6f9c2 100644 (file)
@@ -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
index ff6e628..73f05e4 100644 (file)
@@ -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)
 {
 }
index 9a068bb..05750b0 100644 (file)
@@ -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;
 
index f55c290..4c8d48f 100644 (file)
@@ -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)
index 25b254f..4d5aa34 100644 (file)
@@ -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);
index be4f714..03d56e2 100644 (file)
 #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
index 29e856b..3d2b3c6 100644 (file)
@@ -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
index a249fba..fbc6099 100644 (file)
@@ -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();
index 64bdaf1..21e91de 100644 (file)
@@ -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) {
index 7f0b499..7da4aa5 100644 (file)
@@ -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 (file)
index 0000000..e10575f
--- /dev/null
@@ -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 (file)
index 0000000..5b57cc8
--- /dev/null
@@ -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
 **
 ****************************************************************************/
 
-#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
+
index 3093ddc..3d505c7 100644 (file)
@@ -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;
index 35de8b2..e64ca5d 100644 (file)
@@ -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;
index e35fa52..6337750 100644 (file)
@@ -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);
 
index 33565c4..fefcf7f 100644 (file)
@@ -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:
index 55a6b2b..9e6e09e 100644 (file)
@@ -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();
index 8bb40ce..ebda11f 100644 (file)
 #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"
index af1a2f7..1eaeebd 100644 (file)
 //
 
 #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
index b7e4259..31ad48a 100644 (file)
 
 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)
index a80bb64..219d07a 100644 (file)
@@ -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;
 
index 4ed7cf4..d3748a4 100644 (file)
@@ -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"
 
 
 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
index a0dae77..3d79f9d 100644 (file)
 #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
index 61e3aa3..608b212 100644 (file)
@@ -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 \
index 1a1f5cc..7aa5496 100644 (file)
@@ -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);
index 6fa47d8..114584c 100644 (file)
@@ -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;
index 2649976..9481bb5 100644 (file)
@@ -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();
index e642f11..bbb5e33 100644 (file)
@@ -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;
     }
index 3038d3a..71bbc7f 100644 (file)
@@ -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()
index 8204e33..cc1ada1 100644 (file)
@@ -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;
     }
index 0475eea..eb0f588 100644 (file)
@@ -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()
index 98c5f7d..fa860be 100644 (file)
@@ -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);