src/declarative/qml/qdeclarativecompiledbindings.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp	Thu Jul 22 16:41:55 2010 +0100
@@ -0,0 +1,2878 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define COMPILEDBINDINGS_DEBUG
+
+#include "private/qdeclarativecompiledbindings_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativejsast_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeexpression_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qnumeric.h>
+#include <private/qdeclarativeanchors_p_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativefastproperties_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
+DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
+
+Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
+
+#ifdef __GNUC__
+#  define QML_THREADED_INTERPRETER
+#endif
+
+#define FOR_EACH_QML_INSTR(F) \
+    F(Noop)                    /* Nop */ \
+    F(BindingId)               /* id */ \
+    F(Subscribe)               /* subscribe */ \
+    F(SubscribeId)             /* subscribe */ \
+    F(FetchAndSubscribe)       /* fetchAndSubscribe */ \
+    F(LoadId)                  /* load */ \
+    F(LoadScope)               /* load */ \
+    F(LoadRoot)                /* load */ \
+    F(LoadAttached)            /* attached */ \
+    F(ConvertIntToReal)        /* unaryop */ \
+    F(ConvertRealToInt)        /* unaryop */ \
+    F(Real)                    /* real_value */ \
+    F(Int)                     /* int_value */ \
+    F(Bool)                    /* bool_value */ \
+    F(String)                  /* string_value */ \
+    F(AddReal)                 /* binaryop */ \
+    F(AddInt)                  /* binaryop */ \
+    F(AddString)               /* binaryop */ \
+    F(MinusReal)               /* binaryop */ \
+    F(MinusInt)                /* binaryop */ \
+    F(CompareReal)             /* binaryop */ \
+    F(CompareString)           /* binaryop */ \
+    F(NotCompareReal)          /* binaryop */ \
+    F(NotCompareString)        /* binaryop */ \
+    F(GreaterThanReal)         /* binaryop */ \
+    F(MaxReal)                 /* binaryop */ \
+    F(MinReal)                 /* binaryop */ \
+    F(NewString)               /* construct */ \
+    F(NewUrl)                  /* construct */ \
+    F(CleanupUrl)              /* cleanup */ \
+    F(CleanupString)           /* cleanup */ \
+    F(Copy)                    /* copy */ \
+    F(Fetch)                   /* fetch */ \
+    F(Store)                   /* store */ \
+    F(Skip)                    /* skip */ \
+    F(Done)                    /* done */ \
+    /* Speculative property resolution */ \
+    F(InitString)              /* initstring */ \
+    F(FindGeneric)             /* find */ \
+    F(FindGenericTerminal)     /* find */ \
+    F(FindProperty)            /* find */ \
+    F(FindPropertyTerminal)    /* find */ \
+    F(CleanupGeneric)          /* cleanup */ \
+    F(ConvertGenericToReal)    /* unaryop */ \
+    F(ConvertGenericToBool)    /* unaryop */ \
+    F(ConvertGenericToString)  /* unaryop */ \
+    F(ConvertGenericToUrl)     /* unaryop */
+
+#define QML_INSTR_ENUM(I) I,
+#define QML_INSTR_ADDR(I) &&op_##I,
+
+#ifdef QML_THREADED_INTERPRETER
+#  define QML_BEGIN_INSTR(I) op_##I:
+#  define QML_END_INSTR(I) ++instr; goto *instr->common.code;
+#  define QML_INSTR_HEADER void *code;
+#else
+#  define QML_BEGIN_INSTR(I) case Instr::I:
+#  define QML_END_INSTR(I) break;
+#  define QML_INSTR_HEADER
+#endif
+
+
+using namespace QDeclarativeJS;
+
+namespace {
+// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
+struct Register {
+    void setUndefined() { type = 0; }
+    void setUnknownButDefined() { type = -1; }
+    void setNaN() { setqreal(qSNaN()); }
+    bool isUndefined() const { return type == 0; }
+
+    void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
+    QObject *getQObject() const { return *((QObject **)data); }
+
+    void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
+    qreal getqreal() const { return *((qreal *)data); }
+
+    void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
+    int getint() const { return *((int *)data); }
+
+    void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
+    bool getbool() const { return *((bool *)data); }
+
+    QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
+    QString *getstringptr() { return (QString *)typeDataPtr(); }
+    QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
+    const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
+    const QString *getstringptr() const { return (QString *)typeDataPtr(); }
+    const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+
+    void *typeDataPtr() { return (void *)&data; }
+    void *typeMemory() { return (void *)data; }
+    const void *typeDataPtr() const { return (void *)&data; }
+    const void *typeMemory() const { return (void *)data; }
+
+    int gettype() const { return type; }
+    void settype(int t) { type = t; }
+
+    int type;          // Optional type
+    void *data[2];     // Object stored here
+};
+}
+
+class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
+
+public:
+    QDeclarativeCompiledBindingsPrivate();
+    virtual ~QDeclarativeCompiledBindingsPrivate();
+
+    struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
+        Binding() : enabled(false), updating(0), property(0),
+                    scope(0), target(0), parent(0) {}
+
+        // Inherited from QDeclarativeAbstractBinding
+        virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
+        virtual int propertyIndex();
+        virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
+        virtual void destroy();
+
+        int index:30;
+        bool enabled:1;
+        bool updating:1;
+        int property;
+        QObject *scope;
+        QObject *target;
+
+        QDeclarativeCompiledBindingsPrivate *parent;
+    };
+
+    typedef QDeclarativeNotifierEndpoint Subscription;
+    Subscription *subscriptions;
+    QScriptDeclarativeClass::PersistentIdentifier *identifiers;
+
+    void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
+
+    const char *programData;
+    Binding *m_bindings;
+    quint32 *m_signalTable;
+
+    static int methodCount;
+
+    void init();
+    void run(int instr, QDeclarativeContextData *context, 
+             QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
+
+
+    inline void unsubscribe(int subIndex);
+    inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
+    inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+
+    QDeclarativePropertyCache::Data *findproperty(QObject *obj, 
+                                                  const QScriptDeclarativeClass::Identifier &name,
+                                                  QDeclarativeEnginePrivate *enginePriv, 
+                                                  QDeclarativePropertyCache::Data &local);
+    bool findproperty(QObject *obj, 
+                      Register *output, 
+                      QDeclarativeEnginePrivate *enginePriv,
+                      int subIdx, 
+                      const QScriptDeclarativeClass::Identifier &name,
+                      bool isTerminal);
+    void findgeneric(Register *output,                                 // value output
+                     int subIdx,                                       // Subscription index in config
+                     QDeclarativeContextData *context,                 // Context to search in
+                     const QScriptDeclarativeClass::Identifier &name, 
+                     bool isTerminal);
+};
+
+QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
+: subscriptions(0), identifiers(0)
+{
+}
+
+QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
+{
+    delete [] subscriptions; subscriptions = 0;
+    delete [] identifiers; identifiers = 0;
+}
+
+int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
+
+QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
+: QObject(*(new QDeclarativeCompiledBindingsPrivate))
+{
+    Q_D(QDeclarativeCompiledBindings);
+
+    if (d->methodCount == -1)
+        d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
+
+    d->programData = program;
+
+    d->init();
+
+    QDeclarativeAbstractExpression::setContext(context);
+}
+
+QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
+{
+    Q_D(QDeclarativeCompiledBindings);
+
+    delete [] d->m_bindings;
+}
+
+QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target, 
+                                                        QObject *scope, int property)
+{
+    Q_D(QDeclarativeCompiledBindings);
+
+    QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
+
+    rv->index = index;
+    rv->property = property;
+    rv->target = target;
+    rv->scope = scope;
+    rv->parent = d;
+
+    addref(); // This is decremented in Binding::destroy()
+
+    return rv;
+}
+
+void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+    if (e) {
+        addToObject(target);
+    } else {
+        removeFromObject();
+    }
+
+    QDeclarativeAbstractBinding::setEnabled(e, flags);
+
+    if (enabled != e) {
+        enabled = e;
+
+        if (e) update(flags);
+    }
+}
+
+int QDeclarativeCompiledBindingsPrivate::Binding::propertyIndex()
+{
+    return property & 0xFFFF;
+}
+
+void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
+{
+    parent->run(this, flags);
+}
+
+void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
+{
+    enabled = false;
+    removeFromObject();
+    clear();
+    parent->q_func()->release();
+}
+
+int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
+{
+    Q_D(QDeclarativeCompiledBindings);
+
+    if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
+        id -= d->methodCount;
+
+        quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
+        quint32 count = *reeval;
+        ++reeval;
+        for (quint32 ii = 0; ii < count; ++ii) {
+            d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
+        }
+    }
+    return -1;
+}
+
+void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+    Q_Q(QDeclarativeCompiledBindings);
+
+    if (!binding->enabled)
+        return;
+
+    QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
+    if (!context || !context->isValid()) 
+        return;
+
+    if (binding->updating) {
+        QString name;
+        if (binding->property & 0xFFFF0000) {
+            QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+            QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+            Q_ASSERT(vt);
+
+            name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
+            name.append(QLatin1String("."));
+            name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
+        } else {
+            name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
+        }
+        qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
+        return;
+    }
+
+    binding->updating = true;
+    if (binding->property & 0xFFFF0000) {
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+        QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+        Q_ASSERT(vt);
+        vt->read(binding->target, binding->property & 0xFFFF);
+
+        QObject *target = vt;
+        run(binding->index, context, binding, binding->scope, target, flags);
+
+        vt->write(binding->target, binding->property & 0xFFFF, flags);
+    } else {
+        run(binding->index, context, binding, binding->scope, binding->target, flags);
+    }
+    binding->updating = false;
+}
+
+namespace {
+// This structure is exactly 8-bytes in size
+struct Instr {
+    enum {
+        FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
+    };
+
+    union {
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            quint8 packing[7];
+        } common;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            quint8 packing;
+            quint16 column;
+            quint32 line;
+        } id;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            quint8 packing[3];
+            quint16 subscriptions;
+            quint16 identifiers;
+        } init;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint16 offset;
+            quint32 index;
+        } subscribe;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[2];
+            quint32 index;
+        } load;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 reg;
+            quint8 exceptionId;
+            quint32 index;
+        } attached;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 reg;
+            quint8 exceptionId;
+            quint32 index;
+        } store;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 objectReg;
+            quint8 exceptionId;
+            quint16 subscription;
+            quint16 function;
+        } fetchAndSubscribe;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 objectReg;
+            quint8 exceptionId;
+            quint32 index;
+        } fetch;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            qint8 src;
+            quint8 packing[5];
+        } copy;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[6];
+        } construct;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[2];
+            float value;
+        } real_value;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[2];
+            int value;
+        } int_value;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            bool value;
+            quint8 packing[5];
+        } bool_value;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint16 length;
+            quint32 offset;
+        } string_value;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 src1;
+            qint8 src2;
+            quint8 packing[4];
+        } binaryop;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 output;
+            qint8 src;
+            quint8 packing[5];
+        } unaryop;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[2];
+            quint32 count;
+        } skip;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            qint8 src;
+            quint8 exceptionId;
+            quint16 name; 
+            quint16 subscribeIndex;
+        } find;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            qint8 reg;
+            quint8 packing[6];
+        } cleanup;
+        struct {
+            QML_INSTR_HEADER
+            quint8 type;
+            quint8 packing[1];
+            quint16 offset;
+            quint32 dataIdx;
+        } initstring;
+    };
+};
+
+struct Program {
+    quint32 bindings;
+    quint32 dataLength;
+    quint32 signalTableOffset;
+    quint32 exceptionDataOffset;
+    quint16 subscriptions;
+    quint16 identifiers;
+    quint16 instructionCount;
+    quint16 compiled;
+
+    const char *data() const { return ((const char *)this) + sizeof(Program); }
+    const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
+};
+}
+
+struct QDeclarativeBindingCompilerPrivate
+{
+    struct Result {
+        Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
+        bool operator==(const Result &o) const { 
+            return unknownType == o.unknownType &&
+                   metaObject == o.metaObject && 
+                   type == o.type &&
+                   reg == o.reg; 
+        }
+        bool operator!=(const Result &o) const { 
+            return !(*this == o);
+        }
+        bool unknownType;
+        const QMetaObject *metaObject;
+        int type;
+        int reg;
+
+        QSet<QString> subscriptionSet;
+    };
+
+    QDeclarativeBindingCompilerPrivate() : registers(0) {}
+
+    void resetInstanceState();
+    int commitCompile();
+
+    QDeclarativeParser::Object *context;
+    QDeclarativeParser::Object *component;
+    QDeclarativeParser::Property *destination;
+    QHash<QString, QDeclarativeParser::Object *> ids;
+    QDeclarativeImports imports;
+    QDeclarativeEnginePrivate *engine;
+
+    QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((intptr_t)context, 16); }
+
+    bool compile(QDeclarativeJS::AST::Node *);
+
+    bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
+
+    bool tryName(QDeclarativeJS::AST::Node *);
+    bool parseName(QDeclarativeJS::AST::Node *, Result &);
+
+    bool tryArith(QDeclarativeJS::AST::Node *);
+    bool parseArith(QDeclarativeJS::AST::Node *, Result &);
+    bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
+    bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
+
+    bool tryLogic(QDeclarativeJS::AST::Node *);
+    bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
+
+    bool tryConditional(QDeclarativeJS::AST::Node *);
+    bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
+
+    bool tryConstant(QDeclarativeJS::AST::Node *);
+    bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
+
+    bool tryMethod(QDeclarativeJS::AST::Node *);
+    bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
+
+    bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
+    bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
+
+    quint32 registers;
+    QHash<int, QPair<int, int> > registerCleanups;
+    int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
+    void registerCleanup(int reg, int cleanup, int cleanupType = 0);
+    void releaseReg(int);
+
+    int registerLiteralString(const QString &);
+    int registerString(const QString &);
+    QHash<QString, QPair<int, int> > registeredStrings;
+    QByteArray data;
+
+    bool subscription(const QStringList &, Result *);
+    int subscriptionIndex(const QStringList &);
+    bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
+
+    quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
+    QVector<quint64> exceptions;
+
+    QSet<int> usedSubscriptionIds;
+    QSet<QString> subscriptionSet;
+    QHash<QString, int> subscriptionIds;
+    QVector<Instr> bytecode;
+
+    // Committed binding data
+    struct {
+        QList<int> offsets;
+        QList<QSet<int> > dependencies;
+
+        QVector<Instr> bytecode;
+        QByteArray data;
+        QHash<QString, int> subscriptionIds;
+        QVector<quint64> exceptions;
+
+        QHash<QString, QPair<int, int> > registeredStrings;
+
+        int count() const { return offsets.count(); }
+    } committed;
+
+    QByteArray buildSignalTable() const;
+    QByteArray buildExceptionData() const;
+};
+
+void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
+{
+    QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+    sub->disconnect();
+}
+
+void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
+{
+    Q_Q(QDeclarativeCompiledBindings);
+
+    unsubscribe(subIndex);
+
+    if (p->idValues[idIndex]) {
+        QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+        sub->target = q;
+        sub->targetMethod = methodCount + subIndex;
+        sub->connect(&p->idValues[idIndex].bindings);
+    }
+}
+ 
+void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
+{
+    Q_Q(QDeclarativeCompiledBindings);
+
+    QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+    sub->target = q;
+    sub->targetMethod = methodCount + subIndex; 
+    if (o)
+        sub->connect(o, notifyIndex);
+    else
+        sub->disconnect();
+}
+
+// Conversion functions - these MUST match the QtScript expression path
+inline static qreal toReal(Register *reg, int type, bool *ok = 0)
+{
+    if (ok) *ok = true;
+
+    if (type == QMetaType::QReal) {
+        return reg->getqreal();
+    } else if (type == qMetaTypeId<QVariant>()) {
+        return reg->getvariantptr()->toReal();
+    } else {
+        if (ok) *ok = false;
+        return 0;
+    }
+}
+
+inline static QString toString(Register *reg, int type, bool *ok = 0)
+{
+    if (ok) *ok = true;
+
+    if (type == QMetaType::QReal) {
+        return QString::number(reg->getqreal());
+    } else if (type == QMetaType::Int) {
+        return QString::number(reg->getint());
+    } else if (type == qMetaTypeId<QVariant>()) {
+        return reg->getvariantptr()->toString();
+    } else if (type == QMetaType::QString) {
+        return *reg->getstringptr();
+    } else {
+        if (ok) *ok = false;
+        return QString();
+    }
+}
+
+inline static bool toBool(Register *reg, int type, bool *ok = 0)
+{
+    if (ok) *ok = true;
+
+    if (type == QMetaType::Bool) {
+        return reg->getbool();
+    } else if (type == qMetaTypeId<QVariant>()) {
+        return reg->getvariantptr()->toBool();
+    } else {
+        if (ok) *ok = false;
+        return false;
+    }
+}
+
+inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
+{
+    if (ok) *ok = true;
+
+    QUrl base;
+    if (type == qMetaTypeId<QVariant>()) {
+        QVariant *var = reg->getvariantptr();
+        int vt = var->type();
+        if (vt == QVariant::Url) {
+            base = var->toUrl();
+        } else if (vt == QVariant::ByteArray) {
+            base = QUrl(QString::fromUtf8(var->toByteArray()));
+        } else if (vt == QVariant::String) {
+            base = QUrl(var->toString());
+        } else {
+            if (ok) *ok = false;
+            return QUrl();
+        }
+    } else if (type == QMetaType::QString) {
+        base = QUrl(*reg->getstringptr());
+    } else {
+        if (ok) *ok = false;
+        return QUrl();
+    }
+
+    if (!base.isEmpty() && base.isRelative())
+        return context->url.resolved(base);
+    else
+        return base;
+}
+
+static QObject *variantToQObject(const QVariant &value, bool *ok)
+{
+    if (ok) *ok = true;
+
+    if (value.userType() == QMetaType::QObjectStar) {
+        return qvariant_cast<QObject*>(value);
+    } else {
+        if (ok) *ok = false;
+        return 0;
+    }
+}
+
+bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, 
+                                                       QDeclarativeEnginePrivate *enginePriv,
+                                                       int subIdx, const QScriptDeclarativeClass::Identifier &name,
+                                                       bool isTerminal)
+{
+    if (!obj) {
+        output->setUndefined();
+        return false;
+    }
+
+    QDeclarativePropertyCache::Data local;
+    QDeclarativePropertyCache::Data *property = 
+        QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
+
+    if (property) {
+        if (subIdx != -1)
+            subscribe(obj, property->notifyIndex, subIdx);
+
+        if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+            void *args[] = { output->typeDataPtr(), 0 };
+            QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+            output->settype(QMetaType::QObjectStar);
+        } else if (property->propType == qMetaTypeId<QVariant>()) {
+            QVariant v;
+            void *args[] = { &v, 0 };
+            QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+
+            if (isTerminal) {
+                new (output->typeDataPtr()) QVariant(v);
+                output->settype(qMetaTypeId<QVariant>());
+            } else {
+                bool ok;
+                output->setQObject(variantToQObject(v, &ok));
+                if (!ok) 
+                    output->setUndefined();
+                else
+                    output->settype(QMetaType::QObjectStar);
+            }
+
+        } else {
+            if (!isTerminal) {
+                output->setUndefined();
+            } else if (property->propType == QMetaType::QReal) {
+                void *args[] = { output->typeDataPtr(), 0 };
+                QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+                output->settype(QMetaType::QReal);
+            } else if (property->propType == QMetaType::Int) {
+                void *args[] = { output->typeDataPtr(), 0 };
+                QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+                output->settype(QMetaType::Int);
+            } else if (property->propType == QMetaType::Bool) {
+                void *args[] = { output->typeDataPtr(), 0 };
+                QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+                output->settype(QMetaType::Bool);
+            } else if (property->propType == QMetaType::QString) {
+                new (output->typeDataPtr()) QString();
+                void *args[] = { output->typeDataPtr(), 0 };
+                QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
+                output->settype(QMetaType::QString);
+            } else {
+                new (output->typeDataPtr()) 
+                    QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
+                output->settype(qMetaTypeId<QVariant>());
+            }
+        }
+
+        return true;
+    } else {
+        output->setUndefined();
+        return false;
+    }
+}
+
+void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, 
+                                                      int subIdx,      
+                                                      QDeclarativeContextData *context,
+                                                      const QScriptDeclarativeClass::Identifier &name, 
+                                                      bool isTerminal)
+{
+    QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
+
+    while (context) {
+
+        int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
+
+
+        if (contextPropertyIndex != -1) {
+
+            if (contextPropertyIndex < context->idValueCount) {
+                output->setQObject(context->idValues[contextPropertyIndex]);
+                output->settype(QMetaType::QObjectStar);
+
+                if (subIdx != -1) 
+                    subscribeId(context, contextPropertyIndex, subIdx);
+
+            } else {
+                QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
+                const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
+
+                if (isTerminal) {
+                    new (output->typeDataPtr()) QVariant(value);
+                    output->settype(qMetaTypeId<QVariant>());
+                } else {
+                    bool ok;
+                    output->setQObject(variantToQObject(value, &ok));
+                    if (!ok) { output->setUndefined(); }
+                    else { output->settype(QMetaType::QObjectStar); }
+                    return;
+                }
+
+                if (subIdx != -1) 
+                    subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
+
+
+            }
+
+            return;
+        }
+
+        if (QObject *root = context->contextObject) {
+
+            if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
+                return;
+
+        }
+
+        context = context->parent;
+    }
+
+    output->setUndefined();
+}
+
+void QDeclarativeCompiledBindingsPrivate::init()
+{
+    Program *program = (Program *)programData;
+    if (program->subscriptions)
+        subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
+    if (program->identifiers)
+        identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
+
+    m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
+    m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
+}
+
+static void throwException(int id, QDeclarativeDelayedError *error, 
+                           Program *program, QDeclarativeContextData *context,
+                           const QString &description = QString())
+{
+    error->error.setUrl(context->url);
+    if (description.isEmpty())
+        error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
+    else
+        error->error.setDescription(description);
+    if (id != 0xFF) {
+        quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
+        error->error.setLine((e >> 32) & 0xFFFFFFFF);
+        error->error.setColumn(e & 0xFFFFFFFF); 
+    } else {
+        error->error.setLine(-1);
+        error->error.setColumn(-1);
+    }
+    if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
+        QDeclarativeEnginePrivate::warning(context->engine, error->error);
+}
+
+static void dumpInstruction(const Instr *instr)
+{
+    switch (instr->common.type) {
+    case Instr::Noop:
+        qWarning().nospace() << "\t" << "Noop";
+        break;
+    case Instr::BindingId:
+        qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
+        break;
+    case Instr::Subscribe:
+        qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
+        break;
+    case Instr::SubscribeId:
+        qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
+        break;
+    case Instr::FetchAndSubscribe:
+        qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
+        break;
+    case Instr::LoadId:
+        qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
+        break;
+    case Instr::LoadScope:
+        qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
+        break;
+    case Instr::LoadRoot:
+        qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
+        break;
+    case Instr::LoadAttached:
+        qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.index;
+        break;
+    case Instr::ConvertIntToReal:
+        qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    case Instr::ConvertRealToInt:
+        qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    case Instr::Real:
+        qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
+        break;
+    case Instr::Int:
+        qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
+        break;
+    case Instr::Bool:
+        qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
+        break;
+    case Instr::String:
+        qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
+        break;
+    case Instr::AddReal:
+        qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::AddInt:
+        qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::AddString:
+        qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::MinusReal:
+        qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::MinusInt:
+        qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::CompareReal:
+        qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::CompareString:
+        qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::NotCompareReal:
+        qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::NotCompareString:
+        qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::GreaterThanReal:
+        qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::MaxReal:
+        qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::MinReal:
+        qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
+        break;
+    case Instr::NewString:
+        qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
+        break;
+    case Instr::NewUrl:
+        qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
+        break;
+    case Instr::CleanupString:
+        qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
+        break;
+    case Instr::CleanupUrl:
+        qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
+        break;
+    case Instr::Fetch:
+        qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
+        break;
+    case Instr::Store:
+        qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
+        break;
+    case Instr::Copy:
+        qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
+        break;
+    case Instr::Skip:
+        qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
+        break;
+    case Instr::Done:
+        qWarning().nospace() << "\t" << "Done";
+        break;
+    case Instr::InitString:
+        qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
+        break;
+    case Instr::FindGeneric:
+        qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
+        break;
+    case Instr::FindGenericTerminal:
+        qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" <<  instr->find.name;
+        break;
+    case Instr::FindProperty:
+        qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
+        break;
+    case Instr::FindPropertyTerminal:
+        qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
+        break;
+    case Instr::CleanupGeneric:
+        qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
+        break;
+    case Instr::ConvertGenericToReal:
+        qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    case Instr::ConvertGenericToBool:
+        qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    case Instr::ConvertGenericToString:
+        qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    case Instr::ConvertGenericToUrl:
+        qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
+        break;
+    default:
+        qWarning().nospace() << "\t" << "Unknown";
+        break;
+    }
+}
+
+void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
+                                              QDeclarativeContextData *context, QDeclarativeDelayedError *error,
+                                              QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
+{
+    Q_Q(QDeclarativeCompiledBindings);
+
+    error->removeError();
+
+    Register registers[32];
+
+    QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
+    Program *program = (Program *)programData;
+    const Instr *instr = program->instructions();
+    instr += instrIndex;
+    const char *data = program->data();
+
+#ifdef QML_THREADED_INTERPRETER
+    static void *decode_instr[] = {
+        FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
+    };
+
+    if (!program->compiled) {
+        program->compiled = true;
+        const Instr *inop = program->instructions();
+        for (int i = 0; i < program->instructionCount; ++i) {
+            Instr *op = (Instr *) inop++;
+            op->common.code = decode_instr[op->common.type];
+        }
+    }
+
+    goto *instr->common.code;
+#else
+    // return;
+
+#ifdef COMPILEDBINDINGS_DEBUG
+    qWarning().nospace() << "Begin binding run";
+#endif
+
+    while (instr) {
+        switch (instr->common.type) {
+
+#ifdef COMPILEDBINDINGS_DEBUG
+        dumpInstruction(instr);
+#endif
+
+#endif
+
+    QML_BEGIN_INSTR(Noop)
+    QML_END_INSTR(Noop)
+
+    QML_BEGIN_INSTR(BindingId)
+    QML_END_INSTR(BindingId)
+
+    QML_BEGIN_INSTR(SubscribeId)
+        subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
+    QML_END_INSTR(SubscribeId)
+
+    QML_BEGIN_INSTR(Subscribe)
+    {
+        QObject *o = 0;
+        const Register &object = registers[instr->subscribe.reg];
+        if (!object.isUndefined()) o = object.getQObject();
+        subscribe(o, instr->subscribe.index, instr->subscribe.offset);
+    }
+    QML_END_INSTR(Subscribe)
+
+    QML_BEGIN_INSTR(FetchAndSubscribe)
+    {
+        const Register &input = registers[instr->fetchAndSubscribe.objectReg];
+        Register &output = registers[instr->fetchAndSubscribe.output];
+
+        if (input.isUndefined()) {
+            throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
+            return;
+        }
+
+        QObject *object = input.getQObject();
+        if (!object) {
+            output.setUndefined();
+        } else {
+            int subIdx = instr->fetchAndSubscribe.subscription;
+            QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
+            if (subIdx != -1) {
+                sub = (subscriptions + subIdx);
+                sub->target = q;
+                sub->targetMethod = methodCount + subIdx; 
+            }
+            fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
+        }
+    }
+    QML_END_INSTR(FetchAndSubscribe)
+
+    QML_BEGIN_INSTR(LoadId)
+        registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
+    QML_END_INSTR(LoadId)
+
+    QML_BEGIN_INSTR(LoadScope)
+        registers[instr->load.reg].setQObject(scope);
+    QML_END_INSTR(LoadScope)
+
+    QML_BEGIN_INSTR(LoadRoot)
+        registers[instr->load.reg].setQObject(context->contextObject);
+    QML_END_INSTR(LoadRoot)
+
+    QML_BEGIN_INSTR(LoadAttached)
+    {
+        const Register &input = registers[instr->attached.reg];
+        Register &output = registers[instr->attached.output];
+        if (input.isUndefined()) {
+            throwException(instr->attached.exceptionId, error, program, context);
+            return;
+        }
+
+        QObject *object = registers[instr->attached.reg].getQObject();
+        if (!object) {
+            output.setUndefined();
+        } else {
+            QObject *attached = 
+                qmlAttachedPropertiesObjectById(instr->attached.index, 
+                                                registers[instr->attached.reg].getQObject(), 
+                                                true);
+            Q_ASSERT(attached);
+            output.setQObject(attached);
+        }
+    }
+    QML_END_INSTR(LoadAttached)
+
+    QML_BEGIN_INSTR(ConvertIntToReal)
+    {
+        const Register &input = registers[instr->unaryop.src];
+        Register &output = registers[instr->unaryop.output];
+        if (input.isUndefined()) output.setUndefined();
+        else output.setqreal(qreal(input.getint()));
+    }
+    QML_END_INSTR(ConvertIntToReal)
+
+    QML_BEGIN_INSTR(ConvertRealToInt)
+    {
+        const Register &input = registers[instr->unaryop.src];
+        Register &output = registers[instr->unaryop.output];
+        if (input.isUndefined()) output.setUndefined();
+        else output.setint(qRound(input.getqreal()));
+    }
+    QML_END_INSTR(ConvertRealToInt)
+
+    QML_BEGIN_INSTR(Real)
+        registers[instr->real_value.reg].setqreal(instr->real_value.value);
+    QML_END_INSTR(Real)
+
+    QML_BEGIN_INSTR(Int)
+        registers[instr->int_value.reg].setint(instr->int_value.value);
+    QML_END_INSTR(Int)
+        
+    QML_BEGIN_INSTR(Bool)
+        registers[instr->bool_value.reg].setbool(instr->bool_value.value);
+    QML_END_INSTR(Bool)
+
+    QML_BEGIN_INSTR(String)
+    {
+        Register &output = registers[instr->string_value.reg];
+        new (output.getstringptr()) 
+            QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
+        output.settype(QMetaType::QString);
+    }
+    QML_END_INSTR(String)
+
+    QML_BEGIN_INSTR(AddReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setqreal(lhs.getqreal() + rhs.getqreal());
+    }
+    QML_END_INSTR(AddReal)
+
+    QML_BEGIN_INSTR(AddInt)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setint(lhs.getint() + rhs.getint());
+    }
+    QML_END_INSTR(AddInt)
+        
+    QML_BEGIN_INSTR(AddString)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
+        else {
+            if (lhs.isUndefined())
+                new (output.getstringptr())
+                    QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
+            else if (rhs.isUndefined())
+                new (output.getstringptr())
+                    QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
+            else
+                new (output.getstringptr()) 
+                    QString(*registers[instr->binaryop.src1].getstringptr() + 
+                            *registers[instr->binaryop.src2].getstringptr());
+            output.settype(QMetaType::QString);
+        }
+    }
+    QML_END_INSTR(AddString)
+
+    QML_BEGIN_INSTR(MinusReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setqreal(lhs.getqreal() - rhs.getqreal());
+    }
+    QML_END_INSTR(MinusReal)
+
+    QML_BEGIN_INSTR(MinusInt)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setint(lhs.getint() - rhs.getint());
+    }
+    QML_END_INSTR(MinusInt)
+
+    QML_BEGIN_INSTR(CompareReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
+        else output.setbool(lhs.getqreal() == rhs.getqreal());
+    }
+    QML_END_INSTR(CompareReal)
+
+    QML_BEGIN_INSTR(CompareString)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
+        else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
+    }
+    QML_END_INSTR(CompareString)
+
+    QML_BEGIN_INSTR(NotCompareReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
+        else output.setbool(lhs.getqreal() != rhs.getqreal());
+    }
+    QML_END_INSTR(NotCompareReal)
+
+    QML_BEGIN_INSTR(NotCompareString)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
+        else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
+    }
+    QML_END_INSTR(NotCompareString)
+
+    QML_BEGIN_INSTR(GreaterThanReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
+        else output.setbool(lhs.getqreal() > rhs.getqreal());
+    }
+    QML_END_INSTR(GreaterThanReal)
+
+    QML_BEGIN_INSTR(MaxReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
+    }
+    QML_END_INSTR(MaxReal)
+
+    QML_BEGIN_INSTR(MinReal)
+    {
+        const Register &lhs = registers[instr->binaryop.src1];
+        const Register &rhs = registers[instr->binaryop.src2];
+        Register &output = registers[instr->binaryop.output];
+        if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
+        else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
+    }
+    QML_END_INSTR(MinReal)
+
+    QML_BEGIN_INSTR(NewString)
+    {
+        Register &output = registers[instr->construct.reg];
+        new (output.getstringptr()) QString;
+        output.settype(QMetaType::QString);
+    }
+    QML_END_INSTR(NewString)
+
+    QML_BEGIN_INSTR(NewUrl)
+    {
+        Register &output = registers[instr->construct.reg];
+        new (output.geturlptr()) QUrl;
+        output.settype(QMetaType::QUrl);
+    }
+    QML_END_INSTR(NewUrl)
+
+    QML_BEGIN_INSTR(CleanupString)
+        registers[instr->cleanup.reg].getstringptr()->~QString();
+    QML_END_INSTR(CleanupString)
+
+    QML_BEGIN_INSTR(CleanupUrl)
+        registers[instr->cleanup.reg].geturlptr()->~QUrl();
+    QML_END_INSTR(CleanupUrl)
+
+    QML_BEGIN_INSTR(Fetch)
+    {
+        const Register &input = registers[instr->fetch.objectReg];
+        Register &output = registers[instr->fetch.output];
+
+        if (input.isUndefined()) {
+            throwException(instr->fetch.exceptionId, error, program, context);
+            return;
+        }
+
+        QObject *object = input.getQObject();
+        if (!object) {
+            output.setUndefined();
+        } else {
+            void *argv[] = { output.typeDataPtr(), 0 };
+            QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
+        }
+    }
+    QML_END_INSTR(Fetch)
+
+    QML_BEGIN_INSTR(Store)
+    {
+        Register &data = registers[instr->store.reg];
+        if (data.isUndefined()) {
+            throwException(instr->store.exceptionId, error, program, context,
+                           QLatin1String("Unable to assign undefined value"));
+            return;
+        }
+
+        int status = -1;
+        void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
+        QMetaObject::metacall(output, QMetaObject::WriteProperty, 
+                              instr->store.index, argv);
+    }
+    QML_END_INSTR(Store)
+
+    QML_BEGIN_INSTR(Copy)
+        registers[instr->copy.reg] = registers[instr->copy.src];
+    QML_END_INSTR(Copy)
+
+    QML_BEGIN_INSTR(Skip)
+        if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) 
+            instr += instr->skip.count;
+    QML_END_INSTR(Skip)
+
+    QML_BEGIN_INSTR(Done)
+        return;
+    QML_END_INSTR(Done)
+
+    QML_BEGIN_INSTR(InitString)
+        if (!identifiers[instr->initstring.offset].identifier) {
+            quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
+            QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); 
+
+            QString str = QString::fromRawData(strdata, len);
+
+            identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+        }
+    QML_END_INSTR(InitString)
+
+    QML_BEGIN_INSTR(FindGenericTerminal)
+        // We start the search in the parent context, as we know that the 
+        // name is not present in the current context or it would have been
+        // found during the static compile
+        findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, 
+                    context->parent,
+                    identifiers[instr->find.name].identifier, 
+                    instr->common.type == Instr::FindGenericTerminal);
+    QML_END_INSTR(FindGenericTerminal)
+
+    QML_BEGIN_INSTR(FindGeneric)
+        // We start the search in the parent context, as we know that the
+        // name is not present in the current context or it would have been
+        // found during the static compile
+        findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
+                    context->parent,
+                    identifiers[instr->find.name].identifier,
+                    instr->common.type == Instr::FindGenericTerminal);
+    QML_END_INSTR(FindGeneric)
+
+    QML_BEGIN_INSTR(FindPropertyTerminal)
+    {
+        const Register &object = registers[instr->find.src];
+        if (object.isUndefined()) {
+            throwException(instr->find.exceptionId, error, program, context);
+            return;
+        }
+
+        findproperty(object.getQObject(), registers + instr->find.reg, 
+                     QDeclarativeEnginePrivate::get(context->engine), 
+                     instr->find.subscribeIndex, identifiers[instr->find.name].identifier, 
+                     instr->common.type == Instr::FindPropertyTerminal);
+    }
+    QML_END_INSTR(FindPropertyTerminal)
+
+    QML_BEGIN_INSTR(FindProperty)
+    {
+        const Register &object = registers[instr->find.src];
+        if (object.isUndefined()) {
+            throwException(instr->find.exceptionId, error, program, context);
+            return;
+        }
+
+        findproperty(object.getQObject(), registers + instr->find.reg,
+                     QDeclarativeEnginePrivate::get(context->engine),
+                     instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
+                     instr->common.type == Instr::FindPropertyTerminal);
+    }
+    QML_END_INSTR(FindProperty)
+
+    QML_BEGIN_INSTR(CleanupGeneric)
+    {
+        int type = registers[instr->cleanup.reg].gettype();
+        if (type == qMetaTypeId<QVariant>()) {
+            registers[instr->cleanup.reg].getvariantptr()->~QVariant();
+        } else if (type == QMetaType::QString) {
+            registers[instr->cleanup.reg].getstringptr()->~QString();
+        } else if (type == QMetaType::QUrl) {
+            registers[instr->cleanup.reg].geturlptr()->~QUrl();
+        }
+    }
+    QML_END_INSTR(CleanupGeneric)
+
+    QML_BEGIN_INSTR(ConvertGenericToReal)
+    {
+        Register &output = registers[instr->unaryop.output];
+        Register &input = registers[instr->unaryop.src];
+        bool ok = true;
+        output.setqreal(toReal(&input, input.gettype(), &ok));
+        if (!ok) output.setUndefined();
+    }
+    QML_END_INSTR(ConvertGenericToReal)
+
+    QML_BEGIN_INSTR(ConvertGenericToBool)
+    {
+        Register &output = registers[instr->unaryop.output];
+        Register &input = registers[instr->unaryop.src];
+        bool ok = true;
+        output.setbool(toBool(&input, input.gettype(), &ok));
+        if (!ok) output.setUndefined();
+    }
+    QML_END_INSTR(ConvertGenericToBool)
+
+    QML_BEGIN_INSTR(ConvertGenericToString)
+    {
+        Register &output = registers[instr->unaryop.output];
+        Register &input = registers[instr->unaryop.src];
+        bool ok = true;
+        QString str = toString(&input, input.gettype(), &ok);
+        if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
+        else { output.setUndefined(); }
+    }
+    QML_END_INSTR(ConvertGenericToString)
+
+    QML_BEGIN_INSTR(ConvertGenericToUrl)
+    {
+        Register &output = registers[instr->unaryop.output];
+        Register &input = registers[instr->unaryop.src];
+        bool ok = true;
+        QUrl url = toUrl(&input, input.gettype(), context, &ok);
+        if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
+        else { output.setUndefined(); }
+    }
+    QML_END_INSTR(ConvertGenericToUrl)
+
+#ifdef QML_THREADED_INTERPRETER
+    // nothing to do
+#else
+    default:
+        qFatal("EEK");
+        break;
+    } // switch
+
+    ++instr;
+    } // while
+#endif
+}
+
+void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
+{
+    const Program *program = (const Program *)programData.constData();
+
+    qWarning() << "Program.bindings:" << program->bindings;
+    qWarning() << "Program.dataLength:" << program->dataLength;
+    qWarning() << "Program.subscriptions:" << program->subscriptions;
+    qWarning() << "Program.indentifiers:" << program->identifiers;
+
+    int count = program->instructionCount;
+    const Instr *instr = program->instructions();
+
+    while (count--) {
+
+        dumpInstruction(instr);
+        ++instr;
+    }
+}
+
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "commited binding" states.
+*/
+void QDeclarativeBindingCompilerPrivate::resetInstanceState()
+{
+    registers = 0;
+    registerCleanups.clear();
+    data = committed.data;
+    exceptions = committed.exceptions;
+    usedSubscriptionIds.clear();
+    subscriptionSet.clear();
+    subscriptionIds = committed.subscriptionIds;
+    registeredStrings = committed.registeredStrings;
+    bytecode.clear();
+}
+
+/*!
+Mark the last compile as successful, and add it to the "committed data"
+section.
+
+Returns the index for the committed binding.
+*/
+int QDeclarativeBindingCompilerPrivate::commitCompile()
+{
+    int rv = committed.count();
+    committed.offsets << committed.bytecode.count();
+    committed.dependencies << usedSubscriptionIds;
+    committed.bytecode << bytecode;
+    committed.data = data;
+    committed.exceptions = exceptions;
+    committed.subscriptionIds = subscriptionIds;
+    committed.registeredStrings = registeredStrings;
+    return rv;
+}
+
+bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
+{
+    resetInstanceState();
+
+    if (destination->type == -1)
+        return false;
+
+    if (bindingsDump()) {
+        QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
+        if (n) {
+            Instr id;
+            id.common.type = Instr::BindingId;
+            id.id.column = n->firstSourceLocation().startColumn;
+            id.id.line = n->firstSourceLocation().startLine;
+            bytecode << id;
+        }
+    }
+
+    Result type;
+
+    if (!parseExpression(node, type)) 
+        return false;
+
+    if (subscriptionSet.count() > 0xFFFF ||
+            registeredStrings.count() > 0xFFFF)
+        return false;
+
+    if (type.unknownType) {
+        if (!qmlExperimental())
+            return false;
+
+        if (destination->type != QMetaType::QReal &&
+            destination->type != QVariant::String &&
+            destination->type != QMetaType::Bool &&
+            destination->type != QVariant::Url)
+            return false;
+
+        int convertReg = acquireReg();
+        if (convertReg == -1)
+            return false;
+
+        if (destination->type == QMetaType::QReal) {
+            Instr convert;
+            convert.common.type = Instr::ConvertGenericToReal;
+            convert.unaryop.output = convertReg;
+            convert.unaryop.src = type.reg;
+            bytecode << convert;
+        } else if (destination->type == QVariant::String) {
+            Instr convert;
+            convert.common.type = Instr::ConvertGenericToString;
+            convert.unaryop.output = convertReg;
+            convert.unaryop.src = type.reg;
+            bytecode << convert;
+        } else if (destination->type == QMetaType::Bool) {
+            Instr convert;
+            convert.common.type = Instr::ConvertGenericToBool;
+            convert.unaryop.output = convertReg;
+            convert.unaryop.src = type.reg;
+            bytecode << convert;
+        } else if (destination->type == QVariant::Url) {
+            Instr convert;
+            convert.common.type = Instr::ConvertGenericToUrl;
+            convert.unaryop.output = convertReg;
+            convert.unaryop.src = type.reg;
+            bytecode << convert;
+        }
+
+        Instr cleanup;
+        cleanup.common.type = Instr::CleanupGeneric;
+        cleanup.cleanup.reg = type.reg;
+        bytecode << cleanup;
+
+        Instr instr;
+        instr.common.type = Instr::Store;
+        instr.store.output = 0;
+        instr.store.index = destination->index;
+        instr.store.reg = convertReg;
+        instr.store.exceptionId = exceptionId(node->expressionCast());
+        bytecode << instr;
+
+        if (destination->type == QVariant::String) {
+            Instr cleanup;
+            cleanup.common.type = Instr::CleanupString;
+            cleanup.cleanup.reg = convertReg;
+            bytecode << cleanup;
+        } else if (destination->type == QVariant::Url) {
+            Instr cleanup;
+            cleanup.common.type = Instr::CleanupUrl;
+            cleanup.cleanup.reg = convertReg;
+            bytecode << cleanup;
+        }
+
+        releaseReg(convertReg);
+
+        Instr done;
+        done.common.type = Instr::Done;
+        bytecode << done;
+
+        return true;
+    } else {
+        // Can we store the final value?
+        if (type.type == QVariant::Int &&
+            destination->type == QMetaType::QReal) {
+            Instr instr;
+            instr.common.type = Instr::ConvertIntToReal;
+            instr.unaryop.output = type.reg;
+            instr.unaryop.src = type.reg;
+            bytecode << instr;
+            type.type = QMetaType::QReal;
+        } else if (type.type == QMetaType::QReal &&
+                   destination->type == QVariant::Int) {
+            Instr instr;
+            instr.common.type = Instr::ConvertRealToInt;
+            instr.unaryop.output = type.reg;
+            instr.unaryop.src = type.reg;
+            bytecode << instr;
+            type.type = QVariant::Int;
+        } else if (type.type == destination->type) {
+        } else {
+            const QMetaObject *from = type.metaObject;
+            const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
+
+            if (QDeclarativePropertyPrivate::canConvert(from, to))
+                type.type = destination->type;
+        }
+
+        if (type.type == destination->type) {
+            Instr instr;
+            instr.common.type = Instr::Store;
+            instr.store.output = 0;
+            instr.store.index = destination->index;
+            instr.store.reg = type.reg;
+            instr.store.exceptionId = exceptionId(node->expressionCast());
+            bytecode << instr;
+
+            releaseReg(type.reg);
+
+            Instr done;
+            done.common.type = Instr::Done;
+            bytecode << done;
+
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
+{
+    while (node->kind == AST::Node::Kind_NestedExpression)
+        node = static_cast<AST::NestedExpression *>(node)->expression;
+
+    if (tryArith(node)) {
+        if (!parseArith(node, type)) return false;
+    } else if (tryLogic(node)) {
+        if (!parseLogic(node, type)) return false;
+    } else if (tryConditional(node)) {
+        if (!parseConditional(node, type)) return false;
+    } else if (tryName(node)) {
+        if (!parseName(node, type)) return false;
+    } else if (tryConstant(node)) {
+        if (!parseConstant(node, type)) return false;
+    } else if (tryMethod(node)) {
+        if (!parseMethod(node, type)) return false;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
+{
+    return node->kind == AST::Node::Kind_IdentifierExpression ||
+           node->kind == AST::Node::Kind_FieldMemberExpression;
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
+{
+    QStringList nameParts;
+    QList<AST::ExpressionNode *> nameNodes;
+    if (!buildName(nameParts, node, &nameNodes))
+        return false;
+
+    int reg = acquireReg();
+    if (reg == -1)
+        return false;
+    type.reg = reg;
+
+    QDeclarativeParser::Object *absType = 0;
+
+    QStringList subscribeName;
+
+    bool wasAttachedObject = false;
+
+    for (int ii = 0; ii < nameParts.count(); ++ii) {
+        const QString &name = nameParts.at(ii);
+
+        // We don't handle signal properties or attached properties
+        if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
+            name.at(2).isUpper())
+            return false;
+
+        QDeclarativeType *attachType = 0;
+        if (name.at(0).isUpper()) {
+            // Could be an attached property
+            if (ii == nameParts.count() - 1)
+                return false;
+            if (nameParts.at(ii + 1).at(0).isUpper())
+                return false;
+
+            QDeclarativeImportedNamespace *ns = 0;
+            if (!engine->importDatabase.resolveType(imports, name.toUtf8(), &attachType, 0, 0, 0, &ns))
+                return false;
+            if (ns || !attachType || !attachType->attachedPropertiesType())
+                return false;
+
+            wasAttachedObject = true;
+        } 
+
+        if (ii == 0) {
+
+            if (attachType) {
+                Instr instr;
+                instr.common.type = Instr::LoadScope;
+                instr.load.index = 0;
+                instr.load.reg = reg;
+                bytecode << instr;
+
+                Instr attach;
+                attach.common.type = Instr::LoadAttached;
+                attach.attached.output = reg;
+                attach.attached.reg = reg;
+                attach.attached.index = attachType->index();
+                attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
+                bytecode << attach;
+
+                subscribeName << contextName();
+                subscribeName << QLatin1String("$$$ATTACH_") + name;
+
+                absType = 0;
+                type.metaObject = attachType->attachedPropertiesType();
+
+                continue;
+            } else if (ids.contains(name)) {
+                QDeclarativeParser::Object *idObject = ids.value(name);
+                absType = idObject;
+                type.metaObject = absType->metaObject();
+
+                // We check if the id object is the root or 
+                // scope object to avoid a subscription
+                if (idObject == component) {
+                    Instr instr;
+                    instr.common.type = Instr::LoadRoot;
+                    instr.load.index = 0;
+                    instr.load.reg = reg;
+                    bytecode << instr;
+                } else if (idObject == context) {
+                    Instr instr;
+                    instr.common.type = Instr::LoadScope;
+                    instr.load.index = 0;
+                    instr.load.reg = reg;
+                    bytecode << instr;
+                } else {
+                    Instr instr;
+                    instr.common.type = Instr::LoadId;
+                    instr.load.index = idObject->idIndex;
+                    instr.load.reg = reg;
+                    bytecode << instr;
+
+                    subscribeName << QLatin1String("$$$ID_") + name;
+
+                    if (subscription(subscribeName, &type)) {
+                        Instr sub;
+                        sub.common.type = Instr::SubscribeId;
+                        sub.subscribe.offset = subscriptionIndex(subscribeName);
+                        sub.subscribe.reg = reg;
+                        sub.subscribe.index = instr.load.index;
+                        bytecode << sub;
+                    }
+                }
+
+            } else {
+
+                QByteArray utf8Name = name.toUtf8();
+                const char *cname = utf8Name.constData();
+
+                int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
+                int d1Idx = -1;
+                if (d0Idx == -1)
+                    d1Idx = component->metaObject()->indexOfProperty(cname);
+
+                if (d0Idx != -1) {
+                    Instr instr;
+                    instr.common.type = Instr::LoadScope;
+                    instr.load.index = 0;
+                    instr.load.reg = reg;
+                    bytecode << instr;
+
+                    subscribeName << contextName();
+                    subscribeName << name;
+
+                    if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
+                        return false;
+                } else if(d1Idx != -1) {
+                    Instr instr;
+                    instr.common.type = Instr::LoadRoot;
+                    instr.load.index = 0;
+                    instr.load.reg = reg;
+                    bytecode << instr;
+
+                    subscribeName << QLatin1String("$$$ROOT");
+                    subscribeName << name;
+
+                    if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
+                        return false;
+                } else if (qmlExperimental()) {
+                    Instr find;
+                    if (nameParts.count() == 1)
+                        find.common.type = Instr::FindGenericTerminal;
+                    else
+                        find.common.type = Instr::FindGeneric;
+
+                    find.find.reg = reg;
+                    find.find.src = -1;
+                    find.find.name = registerString(name);
+                    find.find.exceptionId = exceptionId(nameNodes.at(ii));
+
+                    subscribeName << QString(QLatin1String("$$$Generic_") + name);
+                    if (subscription(subscribeName, &type)) 
+                        find.find.subscribeIndex = subscriptionIndex(subscribeName);
+                    else
+                        find.find.subscribeIndex = -1;
+
+                    bytecode << find;
+                    type.unknownType = true;
+                } 
+
+                if (!type.unknownType && type.type == -1)
+                    return false; // Couldn't fetch that type
+            } 
+
+        } else {
+
+            if (attachType) {
+                Instr attach;
+                attach.common.type = Instr::LoadAttached;
+                attach.attached.output = reg;
+                attach.attached.reg = reg;
+                attach.attached.index = attachType->index();
+                bytecode << attach;
+
+                absType = 0;
+                type.metaObject = attachType->attachedPropertiesType();
+
+                subscribeName << QLatin1String("$$$ATTACH_") + name;
+                continue;
+            }
+
+            const QMetaObject *mo = 0;
+            if (absType)
+                mo = absType->metaObject();
+            else if (type.metaObject)
+                mo = type.metaObject;
+
+            QByteArray utf8Name = name.toUtf8();
+            const char *cname = utf8Name.constData();
+            int idx = mo?mo->indexOfProperty(cname):-1;
+            if (absType && idx == -1)
+                return false;
+
+            subscribeName << name;
+
+            if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
+                absType = 0; 
+                if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
+                    return false;
+            } else {
+
+                Instr prop;
+                if (ii == nameParts.count() -1 ) 
+                    prop.common.type = Instr::FindPropertyTerminal;
+                else
+                    prop.common.type = Instr::FindProperty;
+
+                prop.find.reg = reg;
+                prop.find.src = reg;
+                prop.find.name = registerString(name);
+                prop.find.exceptionId = exceptionId(nameNodes.at(ii));
+
+                if (subscription(subscribeName, &type))
+                    prop.find.subscribeIndex = subscriptionIndex(subscribeName);
+                else
+                    prop.find.subscribeIndex = -1;
+
+                type.unknownType = true;
+                type.metaObject = 0;
+                type.type = -1;
+                type.reg = reg;
+                bytecode << prop;
+            }
+        }
+
+        wasAttachedObject = false;
+    }
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
+{
+    if (node->kind != AST::Node::Kind_BinaryExpression)
+        return false;
+
+    AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
+    if (expression->op == QSOperator::Add ||
+        expression->op == QSOperator::Sub)
+        return true;
+    else
+        return false;
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
+{
+    AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
+
+    type.reg = acquireReg();
+    if (type.reg == -1)
+        return false;
+
+    Result lhs;
+    Result rhs;
+
+    if (!parseExpression(expression->left, lhs)) return false;
+    if (!parseExpression(expression->right, rhs)) return false;
+
+    if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
+        (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
+        return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
+    else if(expression->op == QSOperator::Sub)
+        return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
+    else if ((lhs.type == QMetaType::QString || lhs.unknownType) && 
+             (rhs.type == QMetaType::QString || rhs.unknownType) && 
+             (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
+        return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
+    else
+        return false;
+}
+
+bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
+{
+    bool nativeReal = rhs.type == QMetaType::QReal ||
+                      lhs.type == QMetaType::QReal ||
+                      lhs.unknownType ||
+                      rhs.unknownType;
+
+    if (nativeReal && lhs.type == QMetaType::Int) {
+        Instr convert;
+        convert.common.type = Instr::ConvertIntToReal;
+        convert.unaryop.output = lhs.reg;
+        convert.unaryop.src = lhs.reg;
+        bytecode << convert;
+    }
+
+    if (nativeReal && rhs.type == QMetaType::Int) {
+        Instr convert;
+        convert.common.type = Instr::ConvertIntToReal;
+        convert.unaryop.output = rhs.reg;
+        convert.unaryop.src = rhs.reg;
+        bytecode << convert;
+    }
+
+    int lhsTmp = -1;
+    int rhsTmp = -1;
+
+    if (lhs.unknownType) {
+        if (!qmlExperimental())
+            return false;
+
+        lhsTmp = acquireReg();
+        if (lhsTmp == -1)
+            return false;
+
+        Instr conv;
+        conv.common.type = Instr::ConvertGenericToReal;
+        conv.unaryop.output = lhsTmp;
+        conv.unaryop.src = lhs.reg;
+        bytecode << conv;
+    }
+
+    if (rhs.unknownType) {
+        if (!qmlExperimental())
+            return false;
+
+        rhsTmp = acquireReg();
+        if (rhsTmp == -1)
+            return false;
+
+        Instr conv;
+        conv.common.type = Instr::ConvertGenericToReal;
+        conv.unaryop.output = rhsTmp;
+        conv.unaryop.src = rhs.reg;
+        bytecode << conv;
+    }
+
+    Instr arith;
+    if (op == QSOperator::Add) {
+        arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
+    } else if (op == QSOperator::Sub) {
+        arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
+    } else {
+        qFatal("Unsupported arithmetic operator");
+    }
+
+    arith.binaryop.output = type.reg;
+    arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
+    arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
+    bytecode << arith;
+
+    type.metaObject = 0;
+    type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
+    type.subscriptionSet.unite(lhs.subscriptionSet);
+    type.subscriptionSet.unite(rhs.subscriptionSet);
+
+    if (lhsTmp != -1) releaseReg(lhsTmp);
+    if (rhsTmp != -1) releaseReg(rhsTmp);
+    releaseReg(lhs.reg);
+    releaseReg(rhs.reg);
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
+{
+    if (op != QSOperator::Add)
+        return false;
+
+    int lhsTmp = -1;
+    int rhsTmp = -1;
+
+    if (lhs.unknownType) {
+        if (!qmlExperimental())
+            return false;
+
+        lhsTmp = acquireReg(Instr::CleanupString);
+        if (lhsTmp == -1)
+            return false;
+
+        Instr convert;
+        convert.common.type = Instr::ConvertGenericToString;
+        convert.unaryop.output = lhsTmp;
+        convert.unaryop.src = lhs.reg;
+        bytecode << convert;
+    }
+
+    if (rhs.unknownType) {
+        if (!qmlExperimental())
+            return false;
+
+        rhsTmp = acquireReg(Instr::CleanupString);
+        if (rhsTmp == -1)
+            return false;
+
+        Instr convert;
+        convert.common.type = Instr::ConvertGenericToString;
+        convert.unaryop.output = rhsTmp;
+        convert.unaryop.src = rhs.reg;
+        bytecode << convert;
+    }
+
+    type.reg = acquireReg(Instr::CleanupString);
+    if (type.reg == -1)
+        return false;
+
+    type.type = QMetaType::QString;
+
+    Instr add;
+    add.common.type = Instr::AddString;
+    add.binaryop.output = type.reg;
+    add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
+    add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
+    bytecode << add;
+
+    if (lhsTmp != -1) releaseReg(lhsTmp);
+    if (rhsTmp != -1) releaseReg(rhsTmp);
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
+{
+    if (node->kind != AST::Node::Kind_BinaryExpression)
+        return false;
+
+    AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
+    if (expression->op == QSOperator::Gt ||
+        expression->op == QSOperator::Equal ||
+        expression->op == QSOperator::NotEqual)
+        return true;
+    else
+        return false;
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
+{
+    AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
+
+    Result lhs;
+    Result rhs;
+
+    if (!parseExpression(expression->left, lhs)) return false;
+    if (!parseExpression(expression->right, rhs)) return false;
+
+    type.reg = acquireReg();
+    if (type.reg == -1)
+        return false;
+
+    type.metaObject = 0;
+    type.type = QVariant::Bool;
+
+    if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
+
+        Instr op;
+        if (expression->op == QSOperator::Gt)
+            op.common.type = Instr::GreaterThanReal;
+        else if (expression->op == QSOperator::Equal)
+            op.common.type = Instr::CompareReal;
+        else if (expression->op == QSOperator::NotEqual)
+            op.common.type = Instr::NotCompareReal;
+        else
+            return false;
+        op.binaryop.output = type.reg;
+        op.binaryop.src1 = lhs.reg;
+        op.binaryop.src2 = rhs.reg;
+        bytecode << op;
+
+
+    } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
+
+        Instr op;
+        if (expression->op == QSOperator::Equal)
+            op.common.type = Instr::CompareString;
+        else if (expression->op == QSOperator::NotEqual)
+            op.common.type = Instr::NotCompareString;
+        else
+            return false;
+        op.binaryop.output = type.reg;
+        op.binaryop.src1 = lhs.reg;
+        op.binaryop.src2 = rhs.reg;
+        bytecode << op;
+
+    } else {
+        return false;
+    }
+
+    releaseReg(lhs.reg);
+    releaseReg(rhs.reg);
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
+{
+    return (node->kind == AST::Node::Kind_ConditionalExpression);
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
+{
+    AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
+
+    AST::Node *test = expression->expression;
+    if (test->kind == AST::Node::Kind_NestedExpression)
+        test = static_cast<AST::NestedExpression*>(test)->expression;
+
+    Result etype;
+    if (!parseExpression(test, etype)) return false;
+
+    if (etype.type != QVariant::Bool) 
+        return false;
+
+    Instr skip;
+    skip.common.type = Instr::Skip;
+    skip.skip.reg = etype.reg;
+    skip.skip.count = 0;
+    int skipIdx = bytecode.count();
+    bytecode << skip;
+
+    // Release to allow reuse of reg
+    releaseReg(etype.reg);
+
+    QSet<QString> preSubSet = subscriptionSet;
+
+    // int preConditionalSubscriptions = subscriptionSet.count();
+
+    Result ok;
+    if (!parseExpression(expression->ok, ok)) return false;
+    if (ok.unknownType) return false;
+
+    int skipIdx2 = bytecode.count();
+    skip.skip.reg = -1;
+    bytecode << skip;
+
+    // Release to allow reuse of reg
+    releaseReg(ok.reg);
+    bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
+
+    subscriptionSet = preSubSet;
+
+    Result ko;
+    if (!parseExpression(expression->ko, ko)) return false;
+    if (ko.unknownType) return false;
+
+    // Release to allow reuse of reg
+    releaseReg(ko.reg);
+    bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
+
+    if (ok != ko)
+        return false; // Must be same type and in same register
+
+    subscriptionSet = preSubSet;
+
+    if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
+        return false; // Conditionals cannot introduce new subscriptions
+
+    type = ok;
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
+{
+    return node->kind == AST::Node::Kind_TrueLiteral ||
+           node->kind == AST::Node::Kind_FalseLiteral ||
+           node->kind == AST::Node::Kind_NumericLiteral ||
+           node->kind == AST::Node::Kind_StringLiteral;
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
+{
+    type.metaObject = 0;
+    type.type = -1;
+    type.reg = acquireReg();
+    if (type.reg == -1)
+        return false;
+
+    if (node->kind == AST::Node::Kind_TrueLiteral) {
+        type.type = QVariant::Bool;
+        Instr instr;
+        instr.common.type = Instr::Bool;
+        instr.bool_value.reg = type.reg;
+        instr.bool_value.value = true;
+        bytecode << instr;
+        return true;
+    } else if (node->kind == AST::Node::Kind_FalseLiteral) {
+        type.type = QVariant::Bool;
+        Instr instr;
+        instr.common.type = Instr::Bool;
+        instr.bool_value.reg = type.reg;
+        instr.bool_value.value = false;
+        bytecode << instr;
+        return true;
+    } else if (node->kind == AST::Node::Kind_NumericLiteral) {
+        qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
+
+        if (qreal(float(value)) != value)
+            return false;
+
+        type.type = QMetaType::QReal;
+        Instr instr;
+        instr.common.type = Instr::Real;
+        instr.real_value.reg = type.reg;
+        instr.real_value.value = float(value);
+        bytecode << instr;
+        return true;
+    } else if (node->kind == AST::Node::Kind_StringLiteral) {
+        QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
+        type.type = QMetaType::QString;
+        type.reg = registerLiteralString(str);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
+{
+    return node->kind == AST::Node::Kind_CallExpression; 
+}
+
+bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
+{
+    AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
+
+    QStringList name;
+    if (!buildName(name, expr->base))
+        return false;
+
+    if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
+        return false;
+
+    QString method = name.at(1);
+
+    AST::ArgumentList *args = expr->arguments;
+    if (!args) return false;
+    AST::ExpressionNode *arg0 = args->expression;
+    args = args->next;
+    if (!args) return false;
+    AST::ExpressionNode *arg1 = args->expression;
+    if (args->next != 0) return false;
+    if (!arg0 || !arg1) return false;
+
+    Result r0;
+    if (!parseExpression(arg0, r0)) return false;
+    Result r1;
+    if (!parseExpression(arg1, r1)) return false;
+
+    if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
+        return false;
+
+    Instr op;
+    if (method == QLatin1String("max")) {
+        op.common.type = Instr::MaxReal;
+    } else if (method == QLatin1String("min")) {
+        op.common.type = Instr::MinReal;
+    } else {
+        return false;
+    }
+    // We release early to reuse registers
+    releaseReg(r0.reg);
+    releaseReg(r1.reg);
+
+    op.binaryop.output = acquireReg();
+    if (op.binaryop.output == -1)
+        return false;
+
+    op.binaryop.src1 = r0.reg;
+    op.binaryop.src2 = r1.reg;
+    bytecode << op;
+
+    result.type = QMetaType::QReal;
+    result.reg = op.binaryop.output;
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
+                                       QDeclarativeJS::AST::Node *node,
+                                       QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
+{
+    if (node->kind == AST::Node::Kind_IdentifierExpression) {
+        name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
+        if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
+    } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
+        AST::FieldMemberExpression *expr =
+            static_cast<AST::FieldMemberExpression *>(node);
+
+        if (!buildName(name, expr->base, nodes))
+            return false;
+
+        name << expr->name->asString();
+        if (nodes) *nodes << expr;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, 
+                                               int idx, const QStringList &subName, 
+                                               QDeclarativeJS::AST::ExpressionNode *node)
+{
+    QMetaProperty prop = mo->property(idx);
+    rv.metaObject = 0;
+    rv.type = 0;
+
+    int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
+
+    Instr fetch;
+
+    if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
+        fetch.common.type = Instr::FetchAndSubscribe;
+        fetch.fetchAndSubscribe.objectReg = reg;
+        fetch.fetchAndSubscribe.output = reg;
+        fetch.fetchAndSubscribe.function = fastFetchIndex;
+        fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
+        fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
+    } else {
+        if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
+            Instr sub;
+            sub.common.type = Instr::Subscribe;
+            sub.subscribe.offset = subscriptionIndex(subName);
+            sub.subscribe.reg = reg;
+            sub.subscribe.index = prop.notifySignalIndex();
+            bytecode << sub;
+        }
+
+        fetch.common.type = Instr::Fetch;
+        fetch.fetch.objectReg = reg;
+        fetch.fetch.index = idx;
+        fetch.fetch.output = reg;
+        fetch.fetch.exceptionId = exceptionId(node);
+    }
+
+    rv.type = prop.userType();
+    rv.metaObject = engine->metaObjectForType(rv.type);
+    rv.reg = reg;
+
+    if (rv.type == QMetaType::QString) {
+        int tmp = acquireReg();
+        if (tmp == -1)
+            return false;
+        Instr copy;
+        copy.common.type = Instr::Copy;
+        copy.copy.reg = tmp;
+        copy.copy.src = reg;
+        bytecode << copy;
+        releaseReg(tmp);
+        fetch.fetch.objectReg = tmp;
+
+        Instr setup;
+        setup.common.type = Instr::NewString;
+        setup.construct.reg = reg;
+        bytecode << setup;
+        registerCleanup(reg, Instr::CleanupString);
+    }
+
+    bytecode << fetch;
+
+    if (!rv.metaObject &&
+        rv.type != QMetaType::QReal &&
+        rv.type != QMetaType::Int &&
+        rv.type != QMetaType::Bool &&
+        rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
+        rv.type != QMetaType::QString) {
+        rv.metaObject = 0;
+        rv.type = 0;
+        return false; // Unsupported type (string not supported yet);
+    }
+
+    return true;
+}
+
+void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
+{
+    registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
+}
+
+int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
+{
+    for (int ii = 0; ii < 32; ++ii) {
+        if (!(registers & (1 << ii))) {
+            registers |= (1 << ii);
+
+            if (cleanup != Instr::Noop)
+                registerCleanup(ii, cleanup, cleanupType);
+
+            return ii;
+        }
+    }
+    return -1;
+}
+
+void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
+{
+    Q_ASSERT(reg >= 0 && reg <= 31);
+
+    if (registerCleanups.contains(reg)) {
+        QPair<int, int> c = registerCleanups[reg];
+        registerCleanups.remove(reg);
+        Instr cleanup;
+        cleanup.common.type = (quint8)c.first;
+        cleanup.cleanup.reg = reg;
+        bytecode << cleanup;
+    }
+
+    quint32 mask = 1 << reg;
+    registers &= ~mask;
+}
+
+// Returns a reg
+int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
+{
+    QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+    int offset = data.count();
+    data += strdata;
+
+    int reg = acquireReg(Instr::CleanupString);
+    if (reg == -1)
+        return false;
+
+    Instr string;
+    string.common.type = Instr::String;
+    string.string_value.reg = reg;
+    string.string_value.offset = offset;
+    string.string_value.length = str.length();
+    bytecode << string;
+
+    return reg;
+}
+
+// Returns an identifier offset
+int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
+{
+    Q_ASSERT(!string.isEmpty());
+
+    QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
+
+    if (iter == registeredStrings.end()) {
+        quint32 len = string.length();
+        QByteArray lendata((const char *)&len, sizeof(quint32));
+        QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
+        strdata.prepend(lendata);
+        int rv = data.count();
+        data += strdata;
+
+        iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
+    } 
+
+    Instr reg;
+    reg.common.type = Instr::InitString;
+    reg.initstring.offset = iter->first;
+    reg.initstring.dataIdx = iter->second;
+    bytecode << reg;
+    return reg.initstring.offset;
+}
+
+bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
+{
+    QString str = sub.join(QLatin1String("."));
+    result->subscriptionSet.insert(str);
+
+    if (subscriptionSet.contains(str)) {
+        return false;
+    } else {
+        subscriptionSet.insert(str);
+        return true;
+    }
+}
+
+int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
+{
+    QString str = sub.join(QLatin1String("."));
+    QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+    if (iter == subscriptionIds.end()) 
+        iter = subscriptionIds.insert(str, subscriptionIds.count());
+    usedSubscriptionIds.insert(*iter);
+    return *iter;
+}
+
+/*
+    Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
+    rhs contains no subscriptions that aren't also in base or lhs.
+*/ 
+bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, 
+                                             const QSet<QString> &lhs, 
+                                             const QSet<QString> &rhs)
+{
+    QSet<QString> difflhs = lhs;
+    difflhs.subtract(rhs);
+    QSet<QString> diffrhs = rhs;
+    diffrhs.subtract(lhs);
+
+    difflhs.unite(diffrhs);
+    difflhs.subtract(base);
+
+    return difflhs.isEmpty();
+}
+
+quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
+{
+    quint8 rv = 0xFF;
+    if (n && exceptions.count() < 0xFF) {
+        rv = (quint8)exceptions.count();
+        QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
+        quint64 e = l.startLine;
+        e <<= 32;
+        e |= l.startColumn;
+        exceptions.append(e);
+    }
+    return rv;
+}
+
+QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
+: d(new QDeclarativeBindingCompilerPrivate)
+{
+}
+
+QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
+{
+    delete d; d = 0;
+}
+
+/* 
+Returns true if any bindings were compiled.
+*/
+bool QDeclarativeBindingCompiler::isValid() const
+{
+    return !d->committed.bytecode.isEmpty();
+}
+
+/* 
+-1 on failure, otherwise the binding index to use.
+*/
+int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
+{
+    if (!expression.expression.asAST()) return false;
+
+    if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
+        return -1;
+
+    if (qmlDisableOptimizer())
+        return -1;
+
+    d->context = expression.context;
+    d->component = expression.component;
+    d->destination = expression.property;
+    d->ids = expression.ids;
+    d->imports = expression.imports;
+    d->engine = engine;
+
+    if (d->compile(expression.expression.asAST())) {
+        return d->commitCompile();
+    } else {
+        return -1;
+    }
+}
+
+
+QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
+{
+    QHash<int, QList<int> > table;
+
+    for (int ii = 0; ii < committed.count(); ++ii) {
+        const QSet<int> &deps = committed.dependencies.at(ii);
+        for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter) 
+            table[*iter].append(ii);
+    }
+
+    QVector<quint32> header;
+    QVector<quint32> data;
+    for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
+        header.append(committed.subscriptionIds.count() + data.count());
+        const QList<int> &bindings = table[ii];
+        data.append(bindings.count());
+        for (int jj = 0; jj < bindings.count(); ++jj)
+            data.append(bindings.at(jj));
+    }
+    header << data;
+
+    return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
+}
+
+QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
+{
+    QByteArray rv;
+    rv.resize(committed.exceptions.count() * sizeof(quint64));
+    ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
+    return rv;
+}
+
+/* 
+Returns the compiled program.
+*/
+QByteArray QDeclarativeBindingCompiler::program() const
+{
+    QByteArray programData;
+
+    if (isValid()) {
+        Program prog;
+        prog.bindings = d->committed.count();
+
+        QVector<Instr> bytecode;
+        Instr skip;
+        skip.common.type = Instr::Skip;
+        skip.skip.reg = -1;
+        for (int ii = 0; ii < d->committed.count(); ++ii) {
+            skip.skip.count = d->committed.count() - ii - 1;
+            skip.skip.count+= d->committed.offsets.at(ii);
+            bytecode << skip;
+        }
+        bytecode << d->committed.bytecode;
+
+        QByteArray data = d->committed.data;
+        while (data.count() % 4) data.append('\0');
+        prog.signalTableOffset = data.count();
+        data += d->buildSignalTable();
+        while (data.count() % 4) data.append('\0');
+        prog.exceptionDataOffset = data.count();
+        data += d->buildExceptionData();
+
+        prog.dataLength = 4 * ((data.size() + 3) / 4);
+        prog.subscriptions = d->committed.subscriptionIds.count();
+        prog.identifiers = d->committed.registeredStrings.count();
+        prog.instructionCount = bytecode.count();
+        prog.compiled = false;
+        int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
+        size += prog.dataLength;
+
+        programData.resize(size);
+        memcpy(programData.data(), &prog, sizeof(Program));
+        if (prog.dataLength)
+            memcpy((char *)((Program *)programData.data())->data(), data.constData(), 
+                   data.size());
+        memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), 
+               bytecode.count() * sizeof(Instr));
+    } 
+
+    return programData;
+}
+
+
+
+QT_END_NAMESPACE