src/declarative/qml/qdeclarativecompiledbindings.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 // #define COMPILEDBINDINGS_DEBUG
       
    43 
       
    44 #include "private/qdeclarativecompiledbindings_p.h"
       
    45 
       
    46 #include <QtDeclarative/qdeclarativeinfo.h>
       
    47 #include <private/qdeclarativecontext_p.h>
       
    48 #include <private/qdeclarativejsast_p.h>
       
    49 #include <private/qdeclarativejsengine_p.h>
       
    50 #include <private/qdeclarativeexpression_p.h>
       
    51 #include <QtCore/qcoreapplication.h>
       
    52 #include <QtCore/qdebug.h>
       
    53 #include <QtCore/qnumeric.h>
       
    54 #include <private/qdeclarativeanchors_p_p.h>
       
    55 #include <private/qdeclarativeglobal_p.h>
       
    56 #include <private/qdeclarativefastproperties_p.h>
       
    57 
       
    58 QT_BEGIN_NAMESPACE
       
    59 
       
    60 DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
       
    61 DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
       
    62 DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
       
    63 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
       
    64 
       
    65 Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
       
    66 
       
    67 #ifdef __GNUC__
       
    68 #  define QML_THREADED_INTERPRETER
       
    69 #endif
       
    70 
       
    71 #define FOR_EACH_QML_INSTR(F) \
       
    72     F(Noop)                    /* Nop */ \
       
    73     F(BindingId)               /* id */ \
       
    74     F(Subscribe)               /* subscribe */ \
       
    75     F(SubscribeId)             /* subscribe */ \
       
    76     F(FetchAndSubscribe)       /* fetchAndSubscribe */ \
       
    77     F(LoadId)                  /* load */ \
       
    78     F(LoadScope)               /* load */ \
       
    79     F(LoadRoot)                /* load */ \
       
    80     F(LoadAttached)            /* attached */ \
       
    81     F(ConvertIntToReal)        /* unaryop */ \
       
    82     F(ConvertRealToInt)        /* unaryop */ \
       
    83     F(Real)                    /* real_value */ \
       
    84     F(Int)                     /* int_value */ \
       
    85     F(Bool)                    /* bool_value */ \
       
    86     F(String)                  /* string_value */ \
       
    87     F(AddReal)                 /* binaryop */ \
       
    88     F(AddInt)                  /* binaryop */ \
       
    89     F(AddString)               /* binaryop */ \
       
    90     F(MinusReal)               /* binaryop */ \
       
    91     F(MinusInt)                /* binaryop */ \
       
    92     F(CompareReal)             /* binaryop */ \
       
    93     F(CompareString)           /* binaryop */ \
       
    94     F(NotCompareReal)          /* binaryop */ \
       
    95     F(NotCompareString)        /* binaryop */ \
       
    96     F(GreaterThanReal)         /* binaryop */ \
       
    97     F(MaxReal)                 /* binaryop */ \
       
    98     F(MinReal)                 /* binaryop */ \
       
    99     F(NewString)               /* construct */ \
       
   100     F(NewUrl)                  /* construct */ \
       
   101     F(CleanupUrl)              /* cleanup */ \
       
   102     F(CleanupString)           /* cleanup */ \
       
   103     F(Copy)                    /* copy */ \
       
   104     F(Fetch)                   /* fetch */ \
       
   105     F(Store)                   /* store */ \
       
   106     F(Skip)                    /* skip */ \
       
   107     F(Done)                    /* done */ \
       
   108     /* Speculative property resolution */ \
       
   109     F(InitString)              /* initstring */ \
       
   110     F(FindGeneric)             /* find */ \
       
   111     F(FindGenericTerminal)     /* find */ \
       
   112     F(FindProperty)            /* find */ \
       
   113     F(FindPropertyTerminal)    /* find */ \
       
   114     F(CleanupGeneric)          /* cleanup */ \
       
   115     F(ConvertGenericToReal)    /* unaryop */ \
       
   116     F(ConvertGenericToBool)    /* unaryop */ \
       
   117     F(ConvertGenericToString)  /* unaryop */ \
       
   118     F(ConvertGenericToUrl)     /* unaryop */
       
   119 
       
   120 #define QML_INSTR_ENUM(I) I,
       
   121 #define QML_INSTR_ADDR(I) &&op_##I,
       
   122 
       
   123 #ifdef QML_THREADED_INTERPRETER
       
   124 #  define QML_BEGIN_INSTR(I) op_##I:
       
   125 #  define QML_END_INSTR(I) ++instr; goto *instr->common.code;
       
   126 #  define QML_INSTR_HEADER void *code;
       
   127 #else
       
   128 #  define QML_BEGIN_INSTR(I) case Instr::I:
       
   129 #  define QML_END_INSTR(I) break;
       
   130 #  define QML_INSTR_HEADER
       
   131 #endif
       
   132 
       
   133 
       
   134 using namespace QDeclarativeJS;
       
   135 
       
   136 namespace {
       
   137 // Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
       
   138 struct Register {
       
   139     void setUndefined() { type = 0; }
       
   140     void setUnknownButDefined() { type = -1; }
       
   141     void setNaN() { setqreal(qSNaN()); }
       
   142     bool isUndefined() const { return type == 0; }
       
   143 
       
   144     void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
       
   145     QObject *getQObject() const { return *((QObject **)data); }
       
   146 
       
   147     void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
       
   148     qreal getqreal() const { return *((qreal *)data); }
       
   149 
       
   150     void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
       
   151     int getint() const { return *((int *)data); }
       
   152 
       
   153     void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
       
   154     bool getbool() const { return *((bool *)data); }
       
   155 
       
   156     QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
       
   157     QString *getstringptr() { return (QString *)typeDataPtr(); }
       
   158     QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
       
   159     const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
       
   160     const QString *getstringptr() const { return (QString *)typeDataPtr(); }
       
   161     const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
       
   162 
       
   163     void *typeDataPtr() { return (void *)&data; }
       
   164     void *typeMemory() { return (void *)data; }
       
   165     const void *typeDataPtr() const { return (void *)&data; }
       
   166     const void *typeMemory() const { return (void *)data; }
       
   167 
       
   168     int gettype() const { return type; }
       
   169     void settype(int t) { type = t; }
       
   170 
       
   171     int type;          // Optional type
       
   172     void *data[2];     // Object stored here
       
   173 };
       
   174 }
       
   175 
       
   176 class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
       
   177 {
       
   178     Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
       
   179 
       
   180 public:
       
   181     QDeclarativeCompiledBindingsPrivate();
       
   182     virtual ~QDeclarativeCompiledBindingsPrivate();
       
   183 
       
   184     struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
       
   185         Binding() : enabled(false), updating(0), property(0),
       
   186                     scope(0), target(0), parent(0) {}
       
   187 
       
   188         // Inherited from QDeclarativeAbstractBinding
       
   189         virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
       
   190         virtual int propertyIndex();
       
   191         virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
       
   192         virtual void destroy();
       
   193 
       
   194         int index:30;
       
   195         bool enabled:1;
       
   196         bool updating:1;
       
   197         int property;
       
   198         QObject *scope;
       
   199         QObject *target;
       
   200 
       
   201         QDeclarativeCompiledBindingsPrivate *parent;
       
   202     };
       
   203 
       
   204     typedef QDeclarativeNotifierEndpoint Subscription;
       
   205     Subscription *subscriptions;
       
   206     QScriptDeclarativeClass::PersistentIdentifier *identifiers;
       
   207 
       
   208     void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
       
   209 
       
   210     const char *programData;
       
   211     Binding *m_bindings;
       
   212     quint32 *m_signalTable;
       
   213 
       
   214     static int methodCount;
       
   215 
       
   216     void init();
       
   217     void run(int instr, QDeclarativeContextData *context, 
       
   218              QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
       
   219 
       
   220 
       
   221     inline void unsubscribe(int subIndex);
       
   222     inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
       
   223     inline void subscribe(QObject *o, int notifyIndex, int subIndex);
       
   224 
       
   225     QDeclarativePropertyCache::Data *findproperty(QObject *obj, 
       
   226                                                   const QScriptDeclarativeClass::Identifier &name,
       
   227                                                   QDeclarativeEnginePrivate *enginePriv, 
       
   228                                                   QDeclarativePropertyCache::Data &local);
       
   229     bool findproperty(QObject *obj, 
       
   230                       Register *output, 
       
   231                       QDeclarativeEnginePrivate *enginePriv,
       
   232                       int subIdx, 
       
   233                       const QScriptDeclarativeClass::Identifier &name,
       
   234                       bool isTerminal);
       
   235     void findgeneric(Register *output,                                 // value output
       
   236                      int subIdx,                                       // Subscription index in config
       
   237                      QDeclarativeContextData *context,                 // Context to search in
       
   238                      const QScriptDeclarativeClass::Identifier &name, 
       
   239                      bool isTerminal);
       
   240 };
       
   241 
       
   242 QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
       
   243 : subscriptions(0), identifiers(0)
       
   244 {
       
   245 }
       
   246 
       
   247 QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
       
   248 {
       
   249     delete [] subscriptions; subscriptions = 0;
       
   250     delete [] identifiers; identifiers = 0;
       
   251 }
       
   252 
       
   253 int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
       
   254 
       
   255 QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
       
   256 : QObject(*(new QDeclarativeCompiledBindingsPrivate))
       
   257 {
       
   258     Q_D(QDeclarativeCompiledBindings);
       
   259 
       
   260     if (d->methodCount == -1)
       
   261         d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
       
   262 
       
   263     d->programData = program;
       
   264 
       
   265     d->init();
       
   266 
       
   267     QDeclarativeAbstractExpression::setContext(context);
       
   268 }
       
   269 
       
   270 QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
       
   271 {
       
   272     Q_D(QDeclarativeCompiledBindings);
       
   273 
       
   274     delete [] d->m_bindings;
       
   275 }
       
   276 
       
   277 QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target, 
       
   278                                                         QObject *scope, int property)
       
   279 {
       
   280     Q_D(QDeclarativeCompiledBindings);
       
   281 
       
   282     QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
       
   283 
       
   284     rv->index = index;
       
   285     rv->property = property;
       
   286     rv->target = target;
       
   287     rv->scope = scope;
       
   288     rv->parent = d;
       
   289 
       
   290     addref(); // This is decremented in Binding::destroy()
       
   291 
       
   292     return rv;
       
   293 }
       
   294 
       
   295 void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
       
   296 {
       
   297     if (e) {
       
   298         addToObject(target);
       
   299     } else {
       
   300         removeFromObject();
       
   301     }
       
   302 
       
   303     QDeclarativeAbstractBinding::setEnabled(e, flags);
       
   304 
       
   305     if (enabled != e) {
       
   306         enabled = e;
       
   307 
       
   308         if (e) update(flags);
       
   309     }
       
   310 }
       
   311 
       
   312 int QDeclarativeCompiledBindingsPrivate::Binding::propertyIndex()
       
   313 {
       
   314     return property & 0xFFFF;
       
   315 }
       
   316 
       
   317 void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
       
   318 {
       
   319     parent->run(this, flags);
       
   320 }
       
   321 
       
   322 void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
       
   323 {
       
   324     enabled = false;
       
   325     removeFromObject();
       
   326     clear();
       
   327     parent->q_func()->release();
       
   328 }
       
   329 
       
   330 int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
       
   331 {
       
   332     Q_D(QDeclarativeCompiledBindings);
       
   333 
       
   334     if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
       
   335         id -= d->methodCount;
       
   336 
       
   337         quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
       
   338         quint32 count = *reeval;
       
   339         ++reeval;
       
   340         for (quint32 ii = 0; ii < count; ++ii) {
       
   341             d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
       
   342         }
       
   343     }
       
   344     return -1;
       
   345 }
       
   346 
       
   347 void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
       
   348 {
       
   349     Q_Q(QDeclarativeCompiledBindings);
       
   350 
       
   351     if (!binding->enabled)
       
   352         return;
       
   353 
       
   354     QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
       
   355     if (!context || !context->isValid()) 
       
   356         return;
       
   357 
       
   358     if (binding->updating) {
       
   359         QString name;
       
   360         if (binding->property & 0xFFFF0000) {
       
   361             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
       
   362 
       
   363             QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
       
   364             Q_ASSERT(vt);
       
   365 
       
   366             name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
       
   367             name.append(QLatin1String("."));
       
   368             name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
       
   369         } else {
       
   370             name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
       
   371         }
       
   372         qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
       
   373         return;
       
   374     }
       
   375 
       
   376     binding->updating = true;
       
   377     if (binding->property & 0xFFFF0000) {
       
   378         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
       
   379 
       
   380         QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
       
   381         Q_ASSERT(vt);
       
   382         vt->read(binding->target, binding->property & 0xFFFF);
       
   383 
       
   384         QObject *target = vt;
       
   385         run(binding->index, context, binding, binding->scope, target, flags);
       
   386 
       
   387         vt->write(binding->target, binding->property & 0xFFFF, flags);
       
   388     } else {
       
   389         run(binding->index, context, binding, binding->scope, binding->target, flags);
       
   390     }
       
   391     binding->updating = false;
       
   392 }
       
   393 
       
   394 namespace {
       
   395 // This structure is exactly 8-bytes in size
       
   396 struct Instr {
       
   397     enum {
       
   398         FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
       
   399     };
       
   400 
       
   401     union {
       
   402         struct {
       
   403             QML_INSTR_HEADER
       
   404             quint8 type;
       
   405             quint8 packing[7];
       
   406         } common;
       
   407         struct {
       
   408             QML_INSTR_HEADER
       
   409             quint8 type;
       
   410             quint8 packing;
       
   411             quint16 column;
       
   412             quint32 line;
       
   413         } id;
       
   414         struct {
       
   415             QML_INSTR_HEADER
       
   416             quint8 type;
       
   417             quint8 packing[3];
       
   418             quint16 subscriptions;
       
   419             quint16 identifiers;
       
   420         } init;
       
   421         struct {
       
   422             QML_INSTR_HEADER
       
   423             quint8 type;
       
   424             qint8 reg;
       
   425             quint16 offset;
       
   426             quint32 index;
       
   427         } subscribe;
       
   428         struct {
       
   429             QML_INSTR_HEADER
       
   430             quint8 type;
       
   431             qint8 reg;
       
   432             quint8 packing[2];
       
   433             quint32 index;
       
   434         } load;
       
   435         struct {
       
   436             QML_INSTR_HEADER
       
   437             quint8 type;
       
   438             qint8 output;
       
   439             qint8 reg;
       
   440             quint8 exceptionId;
       
   441             quint32 index;
       
   442         } attached;
       
   443         struct {
       
   444             QML_INSTR_HEADER
       
   445             quint8 type;
       
   446             qint8 output;
       
   447             qint8 reg;
       
   448             quint8 exceptionId;
       
   449             quint32 index;
       
   450         } store;
       
   451         struct {
       
   452             QML_INSTR_HEADER
       
   453             quint8 type;
       
   454             qint8 output;
       
   455             qint8 objectReg;
       
   456             quint8 exceptionId;
       
   457             quint16 subscription;
       
   458             quint16 function;
       
   459         } fetchAndSubscribe;
       
   460         struct {
       
   461             QML_INSTR_HEADER
       
   462             quint8 type;
       
   463             qint8 output;
       
   464             qint8 objectReg;
       
   465             quint8 exceptionId;
       
   466             quint32 index;
       
   467         } fetch;
       
   468         struct {
       
   469             QML_INSTR_HEADER
       
   470             quint8 type;
       
   471             qint8 reg;
       
   472             qint8 src;
       
   473             quint8 packing[5];
       
   474         } copy;
       
   475         struct {
       
   476             QML_INSTR_HEADER
       
   477             quint8 type;
       
   478             qint8 reg;
       
   479             quint8 packing[6];
       
   480         } construct;
       
   481         struct {
       
   482             QML_INSTR_HEADER
       
   483             quint8 type;
       
   484             qint8 reg;
       
   485             quint8 packing[2];
       
   486             float value;
       
   487         } real_value;
       
   488         struct {
       
   489             QML_INSTR_HEADER
       
   490             quint8 type;
       
   491             qint8 reg;
       
   492             quint8 packing[2];
       
   493             int value;
       
   494         } int_value;
       
   495         struct {
       
   496             QML_INSTR_HEADER
       
   497             quint8 type;
       
   498             qint8 reg;
       
   499             bool value;
       
   500             quint8 packing[5];
       
   501         } bool_value;
       
   502         struct {
       
   503             QML_INSTR_HEADER
       
   504             quint8 type;
       
   505             qint8 reg;
       
   506             quint16 length;
       
   507             quint32 offset;
       
   508         } string_value;
       
   509         struct {
       
   510             QML_INSTR_HEADER
       
   511             quint8 type;
       
   512             qint8 output;
       
   513             qint8 src1;
       
   514             qint8 src2;
       
   515             quint8 packing[4];
       
   516         } binaryop;
       
   517         struct {
       
   518             QML_INSTR_HEADER
       
   519             quint8 type;
       
   520             qint8 output;
       
   521             qint8 src;
       
   522             quint8 packing[5];
       
   523         } unaryop;
       
   524         struct {
       
   525             QML_INSTR_HEADER
       
   526             quint8 type;
       
   527             qint8 reg;
       
   528             quint8 packing[2];
       
   529             quint32 count;
       
   530         } skip;
       
   531         struct {
       
   532             QML_INSTR_HEADER
       
   533             quint8 type;
       
   534             qint8 reg;
       
   535             qint8 src;
       
   536             quint8 exceptionId;
       
   537             quint16 name; 
       
   538             quint16 subscribeIndex;
       
   539         } find;
       
   540         struct {
       
   541             QML_INSTR_HEADER
       
   542             quint8 type;
       
   543             qint8 reg;
       
   544             quint8 packing[6];
       
   545         } cleanup;
       
   546         struct {
       
   547             QML_INSTR_HEADER
       
   548             quint8 type;
       
   549             quint8 packing[1];
       
   550             quint16 offset;
       
   551             quint32 dataIdx;
       
   552         } initstring;
       
   553     };
       
   554 };
       
   555 
       
   556 struct Program {
       
   557     quint32 bindings;
       
   558     quint32 dataLength;
       
   559     quint32 signalTableOffset;
       
   560     quint32 exceptionDataOffset;
       
   561     quint16 subscriptions;
       
   562     quint16 identifiers;
       
   563     quint16 instructionCount;
       
   564     quint16 compiled;
       
   565 
       
   566     const char *data() const { return ((const char *)this) + sizeof(Program); }
       
   567     const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
       
   568 };
       
   569 }
       
   570 
       
   571 struct QDeclarativeBindingCompilerPrivate
       
   572 {
       
   573     struct Result {
       
   574         Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
       
   575         bool operator==(const Result &o) const { 
       
   576             return unknownType == o.unknownType &&
       
   577                    metaObject == o.metaObject && 
       
   578                    type == o.type &&
       
   579                    reg == o.reg; 
       
   580         }
       
   581         bool operator!=(const Result &o) const { 
       
   582             return !(*this == o);
       
   583         }
       
   584         bool unknownType;
       
   585         const QMetaObject *metaObject;
       
   586         int type;
       
   587         int reg;
       
   588 
       
   589         QSet<QString> subscriptionSet;
       
   590     };
       
   591 
       
   592     QDeclarativeBindingCompilerPrivate() : registers(0) {}
       
   593 
       
   594     void resetInstanceState();
       
   595     int commitCompile();
       
   596 
       
   597     QDeclarativeParser::Object *context;
       
   598     QDeclarativeParser::Object *component;
       
   599     QDeclarativeParser::Property *destination;
       
   600     QHash<QString, QDeclarativeParser::Object *> ids;
       
   601     QDeclarativeImports imports;
       
   602     QDeclarativeEnginePrivate *engine;
       
   603 
       
   604     QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((intptr_t)context, 16); }
       
   605 
       
   606     bool compile(QDeclarativeJS::AST::Node *);
       
   607 
       
   608     bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
       
   609 
       
   610     bool tryName(QDeclarativeJS::AST::Node *);
       
   611     bool parseName(QDeclarativeJS::AST::Node *, Result &);
       
   612 
       
   613     bool tryArith(QDeclarativeJS::AST::Node *);
       
   614     bool parseArith(QDeclarativeJS::AST::Node *, Result &);
       
   615     bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
       
   616     bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
       
   617 
       
   618     bool tryLogic(QDeclarativeJS::AST::Node *);
       
   619     bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
       
   620 
       
   621     bool tryConditional(QDeclarativeJS::AST::Node *);
       
   622     bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
       
   623 
       
   624     bool tryConstant(QDeclarativeJS::AST::Node *);
       
   625     bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
       
   626 
       
   627     bool tryMethod(QDeclarativeJS::AST::Node *);
       
   628     bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
       
   629 
       
   630     bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
       
   631     bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
       
   632 
       
   633     quint32 registers;
       
   634     QHash<int, QPair<int, int> > registerCleanups;
       
   635     int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
       
   636     void registerCleanup(int reg, int cleanup, int cleanupType = 0);
       
   637     void releaseReg(int);
       
   638 
       
   639     int registerLiteralString(const QString &);
       
   640     int registerString(const QString &);
       
   641     QHash<QString, QPair<int, int> > registeredStrings;
       
   642     QByteArray data;
       
   643 
       
   644     bool subscription(const QStringList &, Result *);
       
   645     int subscriptionIndex(const QStringList &);
       
   646     bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
       
   647 
       
   648     quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
       
   649     QVector<quint64> exceptions;
       
   650 
       
   651     QSet<int> usedSubscriptionIds;
       
   652     QSet<QString> subscriptionSet;
       
   653     QHash<QString, int> subscriptionIds;
       
   654     QVector<Instr> bytecode;
       
   655 
       
   656     // Committed binding data
       
   657     struct {
       
   658         QList<int> offsets;
       
   659         QList<QSet<int> > dependencies;
       
   660 
       
   661         QVector<Instr> bytecode;
       
   662         QByteArray data;
       
   663         QHash<QString, int> subscriptionIds;
       
   664         QVector<quint64> exceptions;
       
   665 
       
   666         QHash<QString, QPair<int, int> > registeredStrings;
       
   667 
       
   668         int count() const { return offsets.count(); }
       
   669     } committed;
       
   670 
       
   671     QByteArray buildSignalTable() const;
       
   672     QByteArray buildExceptionData() const;
       
   673 };
       
   674 
       
   675 void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
       
   676 {
       
   677     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
       
   678     sub->disconnect();
       
   679 }
       
   680 
       
   681 void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
       
   682 {
       
   683     Q_Q(QDeclarativeCompiledBindings);
       
   684 
       
   685     unsubscribe(subIndex);
       
   686 
       
   687     if (p->idValues[idIndex]) {
       
   688         QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
       
   689         sub->target = q;
       
   690         sub->targetMethod = methodCount + subIndex;
       
   691         sub->connect(&p->idValues[idIndex].bindings);
       
   692     }
       
   693 }
       
   694  
       
   695 void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
       
   696 {
       
   697     Q_Q(QDeclarativeCompiledBindings);
       
   698 
       
   699     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
       
   700     sub->target = q;
       
   701     sub->targetMethod = methodCount + subIndex; 
       
   702     if (o)
       
   703         sub->connect(o, notifyIndex);
       
   704     else
       
   705         sub->disconnect();
       
   706 }
       
   707 
       
   708 // Conversion functions - these MUST match the QtScript expression path
       
   709 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
       
   710 {
       
   711     if (ok) *ok = true;
       
   712 
       
   713     if (type == QMetaType::QReal) {
       
   714         return reg->getqreal();
       
   715     } else if (type == qMetaTypeId<QVariant>()) {
       
   716         return reg->getvariantptr()->toReal();
       
   717     } else {
       
   718         if (ok) *ok = false;
       
   719         return 0;
       
   720     }
       
   721 }
       
   722 
       
   723 inline static QString toString(Register *reg, int type, bool *ok = 0)
       
   724 {
       
   725     if (ok) *ok = true;
       
   726 
       
   727     if (type == QMetaType::QReal) {
       
   728         return QString::number(reg->getqreal());
       
   729     } else if (type == QMetaType::Int) {
       
   730         return QString::number(reg->getint());
       
   731     } else if (type == qMetaTypeId<QVariant>()) {
       
   732         return reg->getvariantptr()->toString();
       
   733     } else if (type == QMetaType::QString) {
       
   734         return *reg->getstringptr();
       
   735     } else {
       
   736         if (ok) *ok = false;
       
   737         return QString();
       
   738     }
       
   739 }
       
   740 
       
   741 inline static bool toBool(Register *reg, int type, bool *ok = 0)
       
   742 {
       
   743     if (ok) *ok = true;
       
   744 
       
   745     if (type == QMetaType::Bool) {
       
   746         return reg->getbool();
       
   747     } else if (type == qMetaTypeId<QVariant>()) {
       
   748         return reg->getvariantptr()->toBool();
       
   749     } else {
       
   750         if (ok) *ok = false;
       
   751         return false;
       
   752     }
       
   753 }
       
   754 
       
   755 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
       
   756 {
       
   757     if (ok) *ok = true;
       
   758 
       
   759     QUrl base;
       
   760     if (type == qMetaTypeId<QVariant>()) {
       
   761         QVariant *var = reg->getvariantptr();
       
   762         int vt = var->type();
       
   763         if (vt == QVariant::Url) {
       
   764             base = var->toUrl();
       
   765         } else if (vt == QVariant::ByteArray) {
       
   766             base = QUrl(QString::fromUtf8(var->toByteArray()));
       
   767         } else if (vt == QVariant::String) {
       
   768             base = QUrl(var->toString());
       
   769         } else {
       
   770             if (ok) *ok = false;
       
   771             return QUrl();
       
   772         }
       
   773     } else if (type == QMetaType::QString) {
       
   774         base = QUrl(*reg->getstringptr());
       
   775     } else {
       
   776         if (ok) *ok = false;
       
   777         return QUrl();
       
   778     }
       
   779 
       
   780     if (!base.isEmpty() && base.isRelative())
       
   781         return context->url.resolved(base);
       
   782     else
       
   783         return base;
       
   784 }
       
   785 
       
   786 static QObject *variantToQObject(const QVariant &value, bool *ok)
       
   787 {
       
   788     if (ok) *ok = true;
       
   789 
       
   790     if (value.userType() == QMetaType::QObjectStar) {
       
   791         return qvariant_cast<QObject*>(value);
       
   792     } else {
       
   793         if (ok) *ok = false;
       
   794         return 0;
       
   795     }
       
   796 }
       
   797 
       
   798 bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, 
       
   799                                                        QDeclarativeEnginePrivate *enginePriv,
       
   800                                                        int subIdx, const QScriptDeclarativeClass::Identifier &name,
       
   801                                                        bool isTerminal)
       
   802 {
       
   803     if (!obj) {
       
   804         output->setUndefined();
       
   805         return false;
       
   806     }
       
   807 
       
   808     QDeclarativePropertyCache::Data local;
       
   809     QDeclarativePropertyCache::Data *property = 
       
   810         QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
       
   811 
       
   812     if (property) {
       
   813         if (subIdx != -1)
       
   814             subscribe(obj, property->notifyIndex, subIdx);
       
   815 
       
   816         if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
       
   817             void *args[] = { output->typeDataPtr(), 0 };
       
   818             QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   819             output->settype(QMetaType::QObjectStar);
       
   820         } else if (property->propType == qMetaTypeId<QVariant>()) {
       
   821             QVariant v;
       
   822             void *args[] = { &v, 0 };
       
   823             QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   824 
       
   825             if (isTerminal) {
       
   826                 new (output->typeDataPtr()) QVariant(v);
       
   827                 output->settype(qMetaTypeId<QVariant>());
       
   828             } else {
       
   829                 bool ok;
       
   830                 output->setQObject(variantToQObject(v, &ok));
       
   831                 if (!ok) 
       
   832                     output->setUndefined();
       
   833                 else
       
   834                     output->settype(QMetaType::QObjectStar);
       
   835             }
       
   836 
       
   837         } else {
       
   838             if (!isTerminal) {
       
   839                 output->setUndefined();
       
   840             } else if (property->propType == QMetaType::QReal) {
       
   841                 void *args[] = { output->typeDataPtr(), 0 };
       
   842                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   843                 output->settype(QMetaType::QReal);
       
   844             } else if (property->propType == QMetaType::Int) {
       
   845                 void *args[] = { output->typeDataPtr(), 0 };
       
   846                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   847                 output->settype(QMetaType::Int);
       
   848             } else if (property->propType == QMetaType::Bool) {
       
   849                 void *args[] = { output->typeDataPtr(), 0 };
       
   850                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   851                 output->settype(QMetaType::Bool);
       
   852             } else if (property->propType == QMetaType::QString) {
       
   853                 new (output->typeDataPtr()) QString();
       
   854                 void *args[] = { output->typeDataPtr(), 0 };
       
   855                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
       
   856                 output->settype(QMetaType::QString);
       
   857             } else {
       
   858                 new (output->typeDataPtr()) 
       
   859                     QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
       
   860                 output->settype(qMetaTypeId<QVariant>());
       
   861             }
       
   862         }
       
   863 
       
   864         return true;
       
   865     } else {
       
   866         output->setUndefined();
       
   867         return false;
       
   868     }
       
   869 }
       
   870 
       
   871 void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, 
       
   872                                                       int subIdx,      
       
   873                                                       QDeclarativeContextData *context,
       
   874                                                       const QScriptDeclarativeClass::Identifier &name, 
       
   875                                                       bool isTerminal)
       
   876 {
       
   877     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
       
   878 
       
   879     while (context) {
       
   880 
       
   881         int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
       
   882 
       
   883 
       
   884         if (contextPropertyIndex != -1) {
       
   885 
       
   886             if (contextPropertyIndex < context->idValueCount) {
       
   887                 output->setQObject(context->idValues[contextPropertyIndex]);
       
   888                 output->settype(QMetaType::QObjectStar);
       
   889 
       
   890                 if (subIdx != -1) 
       
   891                     subscribeId(context, contextPropertyIndex, subIdx);
       
   892 
       
   893             } else {
       
   894                 QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
       
   895                 const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
       
   896 
       
   897                 if (isTerminal) {
       
   898                     new (output->typeDataPtr()) QVariant(value);
       
   899                     output->settype(qMetaTypeId<QVariant>());
       
   900                 } else {
       
   901                     bool ok;
       
   902                     output->setQObject(variantToQObject(value, &ok));
       
   903                     if (!ok) { output->setUndefined(); }
       
   904                     else { output->settype(QMetaType::QObjectStar); }
       
   905                     return;
       
   906                 }
       
   907 
       
   908                 if (subIdx != -1) 
       
   909                     subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
       
   910 
       
   911 
       
   912             }
       
   913 
       
   914             return;
       
   915         }
       
   916 
       
   917         if (QObject *root = context->contextObject) {
       
   918 
       
   919             if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
       
   920                 return;
       
   921 
       
   922         }
       
   923 
       
   924         context = context->parent;
       
   925     }
       
   926 
       
   927     output->setUndefined();
       
   928 }
       
   929 
       
   930 void QDeclarativeCompiledBindingsPrivate::init()
       
   931 {
       
   932     Program *program = (Program *)programData;
       
   933     if (program->subscriptions)
       
   934         subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
       
   935     if (program->identifiers)
       
   936         identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
       
   937 
       
   938     m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
       
   939     m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
       
   940 }
       
   941 
       
   942 static void throwException(int id, QDeclarativeDelayedError *error, 
       
   943                            Program *program, QDeclarativeContextData *context,
       
   944                            const QString &description = QString())
       
   945 {
       
   946     error->error.setUrl(context->url);
       
   947     if (description.isEmpty())
       
   948         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
       
   949     else
       
   950         error->error.setDescription(description);
       
   951     if (id != 0xFF) {
       
   952         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
       
   953         error->error.setLine((e >> 32) & 0xFFFFFFFF);
       
   954         error->error.setColumn(e & 0xFFFFFFFF); 
       
   955     } else {
       
   956         error->error.setLine(-1);
       
   957         error->error.setColumn(-1);
       
   958     }
       
   959     if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
       
   960         QDeclarativeEnginePrivate::warning(context->engine, error->error);
       
   961 }
       
   962 
       
   963 static void dumpInstruction(const Instr *instr)
       
   964 {
       
   965     switch (instr->common.type) {
       
   966     case Instr::Noop:
       
   967         qWarning().nospace() << "\t" << "Noop";
       
   968         break;
       
   969     case Instr::BindingId:
       
   970         qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
       
   971         break;
       
   972     case Instr::Subscribe:
       
   973         qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
       
   974         break;
       
   975     case Instr::SubscribeId:
       
   976         qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
       
   977         break;
       
   978     case Instr::FetchAndSubscribe:
       
   979         qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
       
   980         break;
       
   981     case Instr::LoadId:
       
   982         qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
       
   983         break;
       
   984     case Instr::LoadScope:
       
   985         qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
       
   986         break;
       
   987     case Instr::LoadRoot:
       
   988         qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
       
   989         break;
       
   990     case Instr::LoadAttached:
       
   991         qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.index;
       
   992         break;
       
   993     case Instr::ConvertIntToReal:
       
   994         qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
   995         break;
       
   996     case Instr::ConvertRealToInt:
       
   997         qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
   998         break;
       
   999     case Instr::Real:
       
  1000         qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
       
  1001         break;
       
  1002     case Instr::Int:
       
  1003         qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
       
  1004         break;
       
  1005     case Instr::Bool:
       
  1006         qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
       
  1007         break;
       
  1008     case Instr::String:
       
  1009         qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
       
  1010         break;
       
  1011     case Instr::AddReal:
       
  1012         qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1013         break;
       
  1014     case Instr::AddInt:
       
  1015         qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1016         break;
       
  1017     case Instr::AddString:
       
  1018         qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1019         break;
       
  1020     case Instr::MinusReal:
       
  1021         qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1022         break;
       
  1023     case Instr::MinusInt:
       
  1024         qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1025         break;
       
  1026     case Instr::CompareReal:
       
  1027         qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1028         break;
       
  1029     case Instr::CompareString:
       
  1030         qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1031         break;
       
  1032     case Instr::NotCompareReal:
       
  1033         qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1034         break;
       
  1035     case Instr::NotCompareString:
       
  1036         qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1037         break;
       
  1038     case Instr::GreaterThanReal:
       
  1039         qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1040         break;
       
  1041     case Instr::MaxReal:
       
  1042         qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1043         break;
       
  1044     case Instr::MinReal:
       
  1045         qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
       
  1046         break;
       
  1047     case Instr::NewString:
       
  1048         qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
       
  1049         break;
       
  1050     case Instr::NewUrl:
       
  1051         qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
       
  1052         break;
       
  1053     case Instr::CleanupString:
       
  1054         qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
       
  1055         break;
       
  1056     case Instr::CleanupUrl:
       
  1057         qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
       
  1058         break;
       
  1059     case Instr::Fetch:
       
  1060         qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
       
  1061         break;
       
  1062     case Instr::Store:
       
  1063         qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
       
  1064         break;
       
  1065     case Instr::Copy:
       
  1066         qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
       
  1067         break;
       
  1068     case Instr::Skip:
       
  1069         qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
       
  1070         break;
       
  1071     case Instr::Done:
       
  1072         qWarning().nospace() << "\t" << "Done";
       
  1073         break;
       
  1074     case Instr::InitString:
       
  1075         qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
       
  1076         break;
       
  1077     case Instr::FindGeneric:
       
  1078         qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
       
  1079         break;
       
  1080     case Instr::FindGenericTerminal:
       
  1081         qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" <<  instr->find.name;
       
  1082         break;
       
  1083     case Instr::FindProperty:
       
  1084         qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
       
  1085         break;
       
  1086     case Instr::FindPropertyTerminal:
       
  1087         qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
       
  1088         break;
       
  1089     case Instr::CleanupGeneric:
       
  1090         qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
       
  1091         break;
       
  1092     case Instr::ConvertGenericToReal:
       
  1093         qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
  1094         break;
       
  1095     case Instr::ConvertGenericToBool:
       
  1096         qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
  1097         break;
       
  1098     case Instr::ConvertGenericToString:
       
  1099         qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
  1100         break;
       
  1101     case Instr::ConvertGenericToUrl:
       
  1102         qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
       
  1103         break;
       
  1104     default:
       
  1105         qWarning().nospace() << "\t" << "Unknown";
       
  1106         break;
       
  1107     }
       
  1108 }
       
  1109 
       
  1110 void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
       
  1111                                               QDeclarativeContextData *context, QDeclarativeDelayedError *error,
       
  1112                                               QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
       
  1113 {
       
  1114     Q_Q(QDeclarativeCompiledBindings);
       
  1115 
       
  1116     error->removeError();
       
  1117 
       
  1118     Register registers[32];
       
  1119 
       
  1120     QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
       
  1121     Program *program = (Program *)programData;
       
  1122     const Instr *instr = program->instructions();
       
  1123     instr += instrIndex;
       
  1124     const char *data = program->data();
       
  1125 
       
  1126 #ifdef QML_THREADED_INTERPRETER
       
  1127     static void *decode_instr[] = {
       
  1128         FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
       
  1129     };
       
  1130 
       
  1131     if (!program->compiled) {
       
  1132         program->compiled = true;
       
  1133         const Instr *inop = program->instructions();
       
  1134         for (int i = 0; i < program->instructionCount; ++i) {
       
  1135             Instr *op = (Instr *) inop++;
       
  1136             op->common.code = decode_instr[op->common.type];
       
  1137         }
       
  1138     }
       
  1139 
       
  1140     goto *instr->common.code;
       
  1141 #else
       
  1142     // return;
       
  1143 
       
  1144 #ifdef COMPILEDBINDINGS_DEBUG
       
  1145     qWarning().nospace() << "Begin binding run";
       
  1146 #endif
       
  1147 
       
  1148     while (instr) {
       
  1149         switch (instr->common.type) {
       
  1150 
       
  1151 #ifdef COMPILEDBINDINGS_DEBUG
       
  1152         dumpInstruction(instr);
       
  1153 #endif
       
  1154 
       
  1155 #endif
       
  1156 
       
  1157     QML_BEGIN_INSTR(Noop)
       
  1158     QML_END_INSTR(Noop)
       
  1159 
       
  1160     QML_BEGIN_INSTR(BindingId)
       
  1161     QML_END_INSTR(BindingId)
       
  1162 
       
  1163     QML_BEGIN_INSTR(SubscribeId)
       
  1164         subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
       
  1165     QML_END_INSTR(SubscribeId)
       
  1166 
       
  1167     QML_BEGIN_INSTR(Subscribe)
       
  1168     {
       
  1169         QObject *o = 0;
       
  1170         const Register &object = registers[instr->subscribe.reg];
       
  1171         if (!object.isUndefined()) o = object.getQObject();
       
  1172         subscribe(o, instr->subscribe.index, instr->subscribe.offset);
       
  1173     }
       
  1174     QML_END_INSTR(Subscribe)
       
  1175 
       
  1176     QML_BEGIN_INSTR(FetchAndSubscribe)
       
  1177     {
       
  1178         const Register &input = registers[instr->fetchAndSubscribe.objectReg];
       
  1179         Register &output = registers[instr->fetchAndSubscribe.output];
       
  1180 
       
  1181         if (input.isUndefined()) {
       
  1182             throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
       
  1183             return;
       
  1184         }
       
  1185 
       
  1186         QObject *object = input.getQObject();
       
  1187         if (!object) {
       
  1188             output.setUndefined();
       
  1189         } else {
       
  1190             int subIdx = instr->fetchAndSubscribe.subscription;
       
  1191             QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
       
  1192             if (subIdx != -1) {
       
  1193                 sub = (subscriptions + subIdx);
       
  1194                 sub->target = q;
       
  1195                 sub->targetMethod = methodCount + subIdx; 
       
  1196             }
       
  1197             fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
       
  1198         }
       
  1199     }
       
  1200     QML_END_INSTR(FetchAndSubscribe)
       
  1201 
       
  1202     QML_BEGIN_INSTR(LoadId)
       
  1203         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
       
  1204     QML_END_INSTR(LoadId)
       
  1205 
       
  1206     QML_BEGIN_INSTR(LoadScope)
       
  1207         registers[instr->load.reg].setQObject(scope);
       
  1208     QML_END_INSTR(LoadScope)
       
  1209 
       
  1210     QML_BEGIN_INSTR(LoadRoot)
       
  1211         registers[instr->load.reg].setQObject(context->contextObject);
       
  1212     QML_END_INSTR(LoadRoot)
       
  1213 
       
  1214     QML_BEGIN_INSTR(LoadAttached)
       
  1215     {
       
  1216         const Register &input = registers[instr->attached.reg];
       
  1217         Register &output = registers[instr->attached.output];
       
  1218         if (input.isUndefined()) {
       
  1219             throwException(instr->attached.exceptionId, error, program, context);
       
  1220             return;
       
  1221         }
       
  1222 
       
  1223         QObject *object = registers[instr->attached.reg].getQObject();
       
  1224         if (!object) {
       
  1225             output.setUndefined();
       
  1226         } else {
       
  1227             QObject *attached = 
       
  1228                 qmlAttachedPropertiesObjectById(instr->attached.index, 
       
  1229                                                 registers[instr->attached.reg].getQObject(), 
       
  1230                                                 true);
       
  1231             Q_ASSERT(attached);
       
  1232             output.setQObject(attached);
       
  1233         }
       
  1234     }
       
  1235     QML_END_INSTR(LoadAttached)
       
  1236 
       
  1237     QML_BEGIN_INSTR(ConvertIntToReal)
       
  1238     {
       
  1239         const Register &input = registers[instr->unaryop.src];
       
  1240         Register &output = registers[instr->unaryop.output];
       
  1241         if (input.isUndefined()) output.setUndefined();
       
  1242         else output.setqreal(qreal(input.getint()));
       
  1243     }
       
  1244     QML_END_INSTR(ConvertIntToReal)
       
  1245 
       
  1246     QML_BEGIN_INSTR(ConvertRealToInt)
       
  1247     {
       
  1248         const Register &input = registers[instr->unaryop.src];
       
  1249         Register &output = registers[instr->unaryop.output];
       
  1250         if (input.isUndefined()) output.setUndefined();
       
  1251         else output.setint(qRound(input.getqreal()));
       
  1252     }
       
  1253     QML_END_INSTR(ConvertRealToInt)
       
  1254 
       
  1255     QML_BEGIN_INSTR(Real)
       
  1256         registers[instr->real_value.reg].setqreal(instr->real_value.value);
       
  1257     QML_END_INSTR(Real)
       
  1258 
       
  1259     QML_BEGIN_INSTR(Int)
       
  1260         registers[instr->int_value.reg].setint(instr->int_value.value);
       
  1261     QML_END_INSTR(Int)
       
  1262         
       
  1263     QML_BEGIN_INSTR(Bool)
       
  1264         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
       
  1265     QML_END_INSTR(Bool)
       
  1266 
       
  1267     QML_BEGIN_INSTR(String)
       
  1268     {
       
  1269         Register &output = registers[instr->string_value.reg];
       
  1270         new (output.getstringptr()) 
       
  1271             QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
       
  1272         output.settype(QMetaType::QString);
       
  1273     }
       
  1274     QML_END_INSTR(String)
       
  1275 
       
  1276     QML_BEGIN_INSTR(AddReal)
       
  1277     {
       
  1278         const Register &lhs = registers[instr->binaryop.src1];
       
  1279         const Register &rhs = registers[instr->binaryop.src2];
       
  1280         Register &output = registers[instr->binaryop.output];
       
  1281         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1282         else output.setqreal(lhs.getqreal() + rhs.getqreal());
       
  1283     }
       
  1284     QML_END_INSTR(AddReal)
       
  1285 
       
  1286     QML_BEGIN_INSTR(AddInt)
       
  1287     {
       
  1288         const Register &lhs = registers[instr->binaryop.src1];
       
  1289         const Register &rhs = registers[instr->binaryop.src2];
       
  1290         Register &output = registers[instr->binaryop.output];
       
  1291         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1292         else output.setint(lhs.getint() + rhs.getint());
       
  1293     }
       
  1294     QML_END_INSTR(AddInt)
       
  1295         
       
  1296     QML_BEGIN_INSTR(AddString)
       
  1297     {
       
  1298         const Register &lhs = registers[instr->binaryop.src1];
       
  1299         const Register &rhs = registers[instr->binaryop.src2];
       
  1300         Register &output = registers[instr->binaryop.output];
       
  1301         if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
       
  1302         else {
       
  1303             if (lhs.isUndefined())
       
  1304                 new (output.getstringptr())
       
  1305                     QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
       
  1306             else if (rhs.isUndefined())
       
  1307                 new (output.getstringptr())
       
  1308                     QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
       
  1309             else
       
  1310                 new (output.getstringptr()) 
       
  1311                     QString(*registers[instr->binaryop.src1].getstringptr() + 
       
  1312                             *registers[instr->binaryop.src2].getstringptr());
       
  1313             output.settype(QMetaType::QString);
       
  1314         }
       
  1315     }
       
  1316     QML_END_INSTR(AddString)
       
  1317 
       
  1318     QML_BEGIN_INSTR(MinusReal)
       
  1319     {
       
  1320         const Register &lhs = registers[instr->binaryop.src1];
       
  1321         const Register &rhs = registers[instr->binaryop.src2];
       
  1322         Register &output = registers[instr->binaryop.output];
       
  1323         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1324         else output.setqreal(lhs.getqreal() - rhs.getqreal());
       
  1325     }
       
  1326     QML_END_INSTR(MinusReal)
       
  1327 
       
  1328     QML_BEGIN_INSTR(MinusInt)
       
  1329     {
       
  1330         const Register &lhs = registers[instr->binaryop.src1];
       
  1331         const Register &rhs = registers[instr->binaryop.src2];
       
  1332         Register &output = registers[instr->binaryop.output];
       
  1333         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1334         else output.setint(lhs.getint() - rhs.getint());
       
  1335     }
       
  1336     QML_END_INSTR(MinusInt)
       
  1337 
       
  1338     QML_BEGIN_INSTR(CompareReal)
       
  1339     {
       
  1340         const Register &lhs = registers[instr->binaryop.src1];
       
  1341         const Register &rhs = registers[instr->binaryop.src2];
       
  1342         Register &output = registers[instr->binaryop.output];
       
  1343         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
       
  1344         else output.setbool(lhs.getqreal() == rhs.getqreal());
       
  1345     }
       
  1346     QML_END_INSTR(CompareReal)
       
  1347 
       
  1348     QML_BEGIN_INSTR(CompareString)
       
  1349     {
       
  1350         const Register &lhs = registers[instr->binaryop.src1];
       
  1351         const Register &rhs = registers[instr->binaryop.src2];
       
  1352         Register &output = registers[instr->binaryop.output];
       
  1353         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
       
  1354         else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
       
  1355     }
       
  1356     QML_END_INSTR(CompareString)
       
  1357 
       
  1358     QML_BEGIN_INSTR(NotCompareReal)
       
  1359     {
       
  1360         const Register &lhs = registers[instr->binaryop.src1];
       
  1361         const Register &rhs = registers[instr->binaryop.src2];
       
  1362         Register &output = registers[instr->binaryop.output];
       
  1363         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
       
  1364         else output.setbool(lhs.getqreal() != rhs.getqreal());
       
  1365     }
       
  1366     QML_END_INSTR(NotCompareReal)
       
  1367 
       
  1368     QML_BEGIN_INSTR(NotCompareString)
       
  1369     {
       
  1370         const Register &lhs = registers[instr->binaryop.src1];
       
  1371         const Register &rhs = registers[instr->binaryop.src2];
       
  1372         Register &output = registers[instr->binaryop.output];
       
  1373         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
       
  1374         else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
       
  1375     }
       
  1376     QML_END_INSTR(NotCompareString)
       
  1377 
       
  1378     QML_BEGIN_INSTR(GreaterThanReal)
       
  1379     {
       
  1380         const Register &lhs = registers[instr->binaryop.src1];
       
  1381         const Register &rhs = registers[instr->binaryop.src2];
       
  1382         Register &output = registers[instr->binaryop.output];
       
  1383         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
       
  1384         else output.setbool(lhs.getqreal() > rhs.getqreal());
       
  1385     }
       
  1386     QML_END_INSTR(GreaterThanReal)
       
  1387 
       
  1388     QML_BEGIN_INSTR(MaxReal)
       
  1389     {
       
  1390         const Register &lhs = registers[instr->binaryop.src1];
       
  1391         const Register &rhs = registers[instr->binaryop.src2];
       
  1392         Register &output = registers[instr->binaryop.output];
       
  1393         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1394         else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
       
  1395     }
       
  1396     QML_END_INSTR(MaxReal)
       
  1397 
       
  1398     QML_BEGIN_INSTR(MinReal)
       
  1399     {
       
  1400         const Register &lhs = registers[instr->binaryop.src1];
       
  1401         const Register &rhs = registers[instr->binaryop.src2];
       
  1402         Register &output = registers[instr->binaryop.output];
       
  1403         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
       
  1404         else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
       
  1405     }
       
  1406     QML_END_INSTR(MinReal)
       
  1407 
       
  1408     QML_BEGIN_INSTR(NewString)
       
  1409     {
       
  1410         Register &output = registers[instr->construct.reg];
       
  1411         new (output.getstringptr()) QString;
       
  1412         output.settype(QMetaType::QString);
       
  1413     }
       
  1414     QML_END_INSTR(NewString)
       
  1415 
       
  1416     QML_BEGIN_INSTR(NewUrl)
       
  1417     {
       
  1418         Register &output = registers[instr->construct.reg];
       
  1419         new (output.geturlptr()) QUrl;
       
  1420         output.settype(QMetaType::QUrl);
       
  1421     }
       
  1422     QML_END_INSTR(NewUrl)
       
  1423 
       
  1424     QML_BEGIN_INSTR(CleanupString)
       
  1425         registers[instr->cleanup.reg].getstringptr()->~QString();
       
  1426     QML_END_INSTR(CleanupString)
       
  1427 
       
  1428     QML_BEGIN_INSTR(CleanupUrl)
       
  1429         registers[instr->cleanup.reg].geturlptr()->~QUrl();
       
  1430     QML_END_INSTR(CleanupUrl)
       
  1431 
       
  1432     QML_BEGIN_INSTR(Fetch)
       
  1433     {
       
  1434         const Register &input = registers[instr->fetch.objectReg];
       
  1435         Register &output = registers[instr->fetch.output];
       
  1436 
       
  1437         if (input.isUndefined()) {
       
  1438             throwException(instr->fetch.exceptionId, error, program, context);
       
  1439             return;
       
  1440         }
       
  1441 
       
  1442         QObject *object = input.getQObject();
       
  1443         if (!object) {
       
  1444             output.setUndefined();
       
  1445         } else {
       
  1446             void *argv[] = { output.typeDataPtr(), 0 };
       
  1447             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
       
  1448         }
       
  1449     }
       
  1450     QML_END_INSTR(Fetch)
       
  1451 
       
  1452     QML_BEGIN_INSTR(Store)
       
  1453     {
       
  1454         Register &data = registers[instr->store.reg];
       
  1455         if (data.isUndefined()) {
       
  1456             throwException(instr->store.exceptionId, error, program, context,
       
  1457                            QLatin1String("Unable to assign undefined value"));
       
  1458             return;
       
  1459         }
       
  1460 
       
  1461         int status = -1;
       
  1462         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
       
  1463         QMetaObject::metacall(output, QMetaObject::WriteProperty, 
       
  1464                               instr->store.index, argv);
       
  1465     }
       
  1466     QML_END_INSTR(Store)
       
  1467 
       
  1468     QML_BEGIN_INSTR(Copy)
       
  1469         registers[instr->copy.reg] = registers[instr->copy.src];
       
  1470     QML_END_INSTR(Copy)
       
  1471 
       
  1472     QML_BEGIN_INSTR(Skip)
       
  1473         if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) 
       
  1474             instr += instr->skip.count;
       
  1475     QML_END_INSTR(Skip)
       
  1476 
       
  1477     QML_BEGIN_INSTR(Done)
       
  1478         return;
       
  1479     QML_END_INSTR(Done)
       
  1480 
       
  1481     QML_BEGIN_INSTR(InitString)
       
  1482         if (!identifiers[instr->initstring.offset].identifier) {
       
  1483             quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
       
  1484             QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); 
       
  1485 
       
  1486             QString str = QString::fromRawData(strdata, len);
       
  1487 
       
  1488             identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
       
  1489         }
       
  1490     QML_END_INSTR(InitString)
       
  1491 
       
  1492     QML_BEGIN_INSTR(FindGenericTerminal)
       
  1493         // We start the search in the parent context, as we know that the 
       
  1494         // name is not present in the current context or it would have been
       
  1495         // found during the static compile
       
  1496         findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, 
       
  1497                     context->parent,
       
  1498                     identifiers[instr->find.name].identifier, 
       
  1499                     instr->common.type == Instr::FindGenericTerminal);
       
  1500     QML_END_INSTR(FindGenericTerminal)
       
  1501 
       
  1502     QML_BEGIN_INSTR(FindGeneric)
       
  1503         // We start the search in the parent context, as we know that the
       
  1504         // name is not present in the current context or it would have been
       
  1505         // found during the static compile
       
  1506         findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
       
  1507                     context->parent,
       
  1508                     identifiers[instr->find.name].identifier,
       
  1509                     instr->common.type == Instr::FindGenericTerminal);
       
  1510     QML_END_INSTR(FindGeneric)
       
  1511 
       
  1512     QML_BEGIN_INSTR(FindPropertyTerminal)
       
  1513     {
       
  1514         const Register &object = registers[instr->find.src];
       
  1515         if (object.isUndefined()) {
       
  1516             throwException(instr->find.exceptionId, error, program, context);
       
  1517             return;
       
  1518         }
       
  1519 
       
  1520         findproperty(object.getQObject(), registers + instr->find.reg, 
       
  1521                      QDeclarativeEnginePrivate::get(context->engine), 
       
  1522                      instr->find.subscribeIndex, identifiers[instr->find.name].identifier, 
       
  1523                      instr->common.type == Instr::FindPropertyTerminal);
       
  1524     }
       
  1525     QML_END_INSTR(FindPropertyTerminal)
       
  1526 
       
  1527     QML_BEGIN_INSTR(FindProperty)
       
  1528     {
       
  1529         const Register &object = registers[instr->find.src];
       
  1530         if (object.isUndefined()) {
       
  1531             throwException(instr->find.exceptionId, error, program, context);
       
  1532             return;
       
  1533         }
       
  1534 
       
  1535         findproperty(object.getQObject(), registers + instr->find.reg,
       
  1536                      QDeclarativeEnginePrivate::get(context->engine),
       
  1537                      instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
       
  1538                      instr->common.type == Instr::FindPropertyTerminal);
       
  1539     }
       
  1540     QML_END_INSTR(FindProperty)
       
  1541 
       
  1542     QML_BEGIN_INSTR(CleanupGeneric)
       
  1543     {
       
  1544         int type = registers[instr->cleanup.reg].gettype();
       
  1545         if (type == qMetaTypeId<QVariant>()) {
       
  1546             registers[instr->cleanup.reg].getvariantptr()->~QVariant();
       
  1547         } else if (type == QMetaType::QString) {
       
  1548             registers[instr->cleanup.reg].getstringptr()->~QString();
       
  1549         } else if (type == QMetaType::QUrl) {
       
  1550             registers[instr->cleanup.reg].geturlptr()->~QUrl();
       
  1551         }
       
  1552     }
       
  1553     QML_END_INSTR(CleanupGeneric)
       
  1554 
       
  1555     QML_BEGIN_INSTR(ConvertGenericToReal)
       
  1556     {
       
  1557         Register &output = registers[instr->unaryop.output];
       
  1558         Register &input = registers[instr->unaryop.src];
       
  1559         bool ok = true;
       
  1560         output.setqreal(toReal(&input, input.gettype(), &ok));
       
  1561         if (!ok) output.setUndefined();
       
  1562     }
       
  1563     QML_END_INSTR(ConvertGenericToReal)
       
  1564 
       
  1565     QML_BEGIN_INSTR(ConvertGenericToBool)
       
  1566     {
       
  1567         Register &output = registers[instr->unaryop.output];
       
  1568         Register &input = registers[instr->unaryop.src];
       
  1569         bool ok = true;
       
  1570         output.setbool(toBool(&input, input.gettype(), &ok));
       
  1571         if (!ok) output.setUndefined();
       
  1572     }
       
  1573     QML_END_INSTR(ConvertGenericToBool)
       
  1574 
       
  1575     QML_BEGIN_INSTR(ConvertGenericToString)
       
  1576     {
       
  1577         Register &output = registers[instr->unaryop.output];
       
  1578         Register &input = registers[instr->unaryop.src];
       
  1579         bool ok = true;
       
  1580         QString str = toString(&input, input.gettype(), &ok);
       
  1581         if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
       
  1582         else { output.setUndefined(); }
       
  1583     }
       
  1584     QML_END_INSTR(ConvertGenericToString)
       
  1585 
       
  1586     QML_BEGIN_INSTR(ConvertGenericToUrl)
       
  1587     {
       
  1588         Register &output = registers[instr->unaryop.output];
       
  1589         Register &input = registers[instr->unaryop.src];
       
  1590         bool ok = true;
       
  1591         QUrl url = toUrl(&input, input.gettype(), context, &ok);
       
  1592         if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
       
  1593         else { output.setUndefined(); }
       
  1594     }
       
  1595     QML_END_INSTR(ConvertGenericToUrl)
       
  1596 
       
  1597 #ifdef QML_THREADED_INTERPRETER
       
  1598     // nothing to do
       
  1599 #else
       
  1600     default:
       
  1601         qFatal("EEK");
       
  1602         break;
       
  1603     } // switch
       
  1604 
       
  1605     ++instr;
       
  1606     } // while
       
  1607 #endif
       
  1608 }
       
  1609 
       
  1610 void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
       
  1611 {
       
  1612     const Program *program = (const Program *)programData.constData();
       
  1613 
       
  1614     qWarning() << "Program.bindings:" << program->bindings;
       
  1615     qWarning() << "Program.dataLength:" << program->dataLength;
       
  1616     qWarning() << "Program.subscriptions:" << program->subscriptions;
       
  1617     qWarning() << "Program.indentifiers:" << program->identifiers;
       
  1618 
       
  1619     int count = program->instructionCount;
       
  1620     const Instr *instr = program->instructions();
       
  1621 
       
  1622     while (count--) {
       
  1623 
       
  1624         dumpInstruction(instr);
       
  1625         ++instr;
       
  1626     }
       
  1627 }
       
  1628 
       
  1629 /*!
       
  1630 Clear the state associated with attempting to compile a specific binding.
       
  1631 This does not clear the global "commited binding" states.
       
  1632 */
       
  1633 void QDeclarativeBindingCompilerPrivate::resetInstanceState()
       
  1634 {
       
  1635     registers = 0;
       
  1636     registerCleanups.clear();
       
  1637     data = committed.data;
       
  1638     exceptions = committed.exceptions;
       
  1639     usedSubscriptionIds.clear();
       
  1640     subscriptionSet.clear();
       
  1641     subscriptionIds = committed.subscriptionIds;
       
  1642     registeredStrings = committed.registeredStrings;
       
  1643     bytecode.clear();
       
  1644 }
       
  1645 
       
  1646 /*!
       
  1647 Mark the last compile as successful, and add it to the "committed data"
       
  1648 section.
       
  1649 
       
  1650 Returns the index for the committed binding.
       
  1651 */
       
  1652 int QDeclarativeBindingCompilerPrivate::commitCompile()
       
  1653 {
       
  1654     int rv = committed.count();
       
  1655     committed.offsets << committed.bytecode.count();
       
  1656     committed.dependencies << usedSubscriptionIds;
       
  1657     committed.bytecode << bytecode;
       
  1658     committed.data = data;
       
  1659     committed.exceptions = exceptions;
       
  1660     committed.subscriptionIds = subscriptionIds;
       
  1661     committed.registeredStrings = registeredStrings;
       
  1662     return rv;
       
  1663 }
       
  1664 
       
  1665 bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
       
  1666 {
       
  1667     resetInstanceState();
       
  1668 
       
  1669     if (destination->type == -1)
       
  1670         return false;
       
  1671 
       
  1672     if (bindingsDump()) {
       
  1673         QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
       
  1674         if (n) {
       
  1675             Instr id;
       
  1676             id.common.type = Instr::BindingId;
       
  1677             id.id.column = n->firstSourceLocation().startColumn;
       
  1678             id.id.line = n->firstSourceLocation().startLine;
       
  1679             bytecode << id;
       
  1680         }
       
  1681     }
       
  1682 
       
  1683     Result type;
       
  1684 
       
  1685     if (!parseExpression(node, type)) 
       
  1686         return false;
       
  1687 
       
  1688     if (subscriptionSet.count() > 0xFFFF ||
       
  1689             registeredStrings.count() > 0xFFFF)
       
  1690         return false;
       
  1691 
       
  1692     if (type.unknownType) {
       
  1693         if (!qmlExperimental())
       
  1694             return false;
       
  1695 
       
  1696         if (destination->type != QMetaType::QReal &&
       
  1697             destination->type != QVariant::String &&
       
  1698             destination->type != QMetaType::Bool &&
       
  1699             destination->type != QVariant::Url)
       
  1700             return false;
       
  1701 
       
  1702         int convertReg = acquireReg();
       
  1703         if (convertReg == -1)
       
  1704             return false;
       
  1705 
       
  1706         if (destination->type == QMetaType::QReal) {
       
  1707             Instr convert;
       
  1708             convert.common.type = Instr::ConvertGenericToReal;
       
  1709             convert.unaryop.output = convertReg;
       
  1710             convert.unaryop.src = type.reg;
       
  1711             bytecode << convert;
       
  1712         } else if (destination->type == QVariant::String) {
       
  1713             Instr convert;
       
  1714             convert.common.type = Instr::ConvertGenericToString;
       
  1715             convert.unaryop.output = convertReg;
       
  1716             convert.unaryop.src = type.reg;
       
  1717             bytecode << convert;
       
  1718         } else if (destination->type == QMetaType::Bool) {
       
  1719             Instr convert;
       
  1720             convert.common.type = Instr::ConvertGenericToBool;
       
  1721             convert.unaryop.output = convertReg;
       
  1722             convert.unaryop.src = type.reg;
       
  1723             bytecode << convert;
       
  1724         } else if (destination->type == QVariant::Url) {
       
  1725             Instr convert;
       
  1726             convert.common.type = Instr::ConvertGenericToUrl;
       
  1727             convert.unaryop.output = convertReg;
       
  1728             convert.unaryop.src = type.reg;
       
  1729             bytecode << convert;
       
  1730         }
       
  1731 
       
  1732         Instr cleanup;
       
  1733         cleanup.common.type = Instr::CleanupGeneric;
       
  1734         cleanup.cleanup.reg = type.reg;
       
  1735         bytecode << cleanup;
       
  1736 
       
  1737         Instr instr;
       
  1738         instr.common.type = Instr::Store;
       
  1739         instr.store.output = 0;
       
  1740         instr.store.index = destination->index;
       
  1741         instr.store.reg = convertReg;
       
  1742         instr.store.exceptionId = exceptionId(node->expressionCast());
       
  1743         bytecode << instr;
       
  1744 
       
  1745         if (destination->type == QVariant::String) {
       
  1746             Instr cleanup;
       
  1747             cleanup.common.type = Instr::CleanupString;
       
  1748             cleanup.cleanup.reg = convertReg;
       
  1749             bytecode << cleanup;
       
  1750         } else if (destination->type == QVariant::Url) {
       
  1751             Instr cleanup;
       
  1752             cleanup.common.type = Instr::CleanupUrl;
       
  1753             cleanup.cleanup.reg = convertReg;
       
  1754             bytecode << cleanup;
       
  1755         }
       
  1756 
       
  1757         releaseReg(convertReg);
       
  1758 
       
  1759         Instr done;
       
  1760         done.common.type = Instr::Done;
       
  1761         bytecode << done;
       
  1762 
       
  1763         return true;
       
  1764     } else {
       
  1765         // Can we store the final value?
       
  1766         if (type.type == QVariant::Int &&
       
  1767             destination->type == QMetaType::QReal) {
       
  1768             Instr instr;
       
  1769             instr.common.type = Instr::ConvertIntToReal;
       
  1770             instr.unaryop.output = type.reg;
       
  1771             instr.unaryop.src = type.reg;
       
  1772             bytecode << instr;
       
  1773             type.type = QMetaType::QReal;
       
  1774         } else if (type.type == QMetaType::QReal &&
       
  1775                    destination->type == QVariant::Int) {
       
  1776             Instr instr;
       
  1777             instr.common.type = Instr::ConvertRealToInt;
       
  1778             instr.unaryop.output = type.reg;
       
  1779             instr.unaryop.src = type.reg;
       
  1780             bytecode << instr;
       
  1781             type.type = QVariant::Int;
       
  1782         } else if (type.type == destination->type) {
       
  1783         } else {
       
  1784             const QMetaObject *from = type.metaObject;
       
  1785             const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
       
  1786 
       
  1787             if (QDeclarativePropertyPrivate::canConvert(from, to))
       
  1788                 type.type = destination->type;
       
  1789         }
       
  1790 
       
  1791         if (type.type == destination->type) {
       
  1792             Instr instr;
       
  1793             instr.common.type = Instr::Store;
       
  1794             instr.store.output = 0;
       
  1795             instr.store.index = destination->index;
       
  1796             instr.store.reg = type.reg;
       
  1797             instr.store.exceptionId = exceptionId(node->expressionCast());
       
  1798             bytecode << instr;
       
  1799 
       
  1800             releaseReg(type.reg);
       
  1801 
       
  1802             Instr done;
       
  1803             done.common.type = Instr::Done;
       
  1804             bytecode << done;
       
  1805 
       
  1806             return true;
       
  1807         } else {
       
  1808             return false;
       
  1809         }
       
  1810     }
       
  1811 }
       
  1812 
       
  1813 bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
       
  1814 {
       
  1815     while (node->kind == AST::Node::Kind_NestedExpression)
       
  1816         node = static_cast<AST::NestedExpression *>(node)->expression;
       
  1817 
       
  1818     if (tryArith(node)) {
       
  1819         if (!parseArith(node, type)) return false;
       
  1820     } else if (tryLogic(node)) {
       
  1821         if (!parseLogic(node, type)) return false;
       
  1822     } else if (tryConditional(node)) {
       
  1823         if (!parseConditional(node, type)) return false;
       
  1824     } else if (tryName(node)) {
       
  1825         if (!parseName(node, type)) return false;
       
  1826     } else if (tryConstant(node)) {
       
  1827         if (!parseConstant(node, type)) return false;
       
  1828     } else if (tryMethod(node)) {
       
  1829         if (!parseMethod(node, type)) return false;
       
  1830     } else {
       
  1831         return false;
       
  1832     }
       
  1833     return true;
       
  1834 }
       
  1835 
       
  1836 bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
       
  1837 {
       
  1838     return node->kind == AST::Node::Kind_IdentifierExpression ||
       
  1839            node->kind == AST::Node::Kind_FieldMemberExpression;
       
  1840 }
       
  1841 
       
  1842 bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
       
  1843 {
       
  1844     QStringList nameParts;
       
  1845     QList<AST::ExpressionNode *> nameNodes;
       
  1846     if (!buildName(nameParts, node, &nameNodes))
       
  1847         return false;
       
  1848 
       
  1849     int reg = acquireReg();
       
  1850     if (reg == -1)
       
  1851         return false;
       
  1852     type.reg = reg;
       
  1853 
       
  1854     QDeclarativeParser::Object *absType = 0;
       
  1855 
       
  1856     QStringList subscribeName;
       
  1857 
       
  1858     bool wasAttachedObject = false;
       
  1859 
       
  1860     for (int ii = 0; ii < nameParts.count(); ++ii) {
       
  1861         const QString &name = nameParts.at(ii);
       
  1862 
       
  1863         // We don't handle signal properties or attached properties
       
  1864         if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
       
  1865             name.at(2).isUpper())
       
  1866             return false;
       
  1867 
       
  1868         QDeclarativeType *attachType = 0;
       
  1869         if (name.at(0).isUpper()) {
       
  1870             // Could be an attached property
       
  1871             if (ii == nameParts.count() - 1)
       
  1872                 return false;
       
  1873             if (nameParts.at(ii + 1).at(0).isUpper())
       
  1874                 return false;
       
  1875 
       
  1876             QDeclarativeImportedNamespace *ns = 0;
       
  1877             if (!engine->importDatabase.resolveType(imports, name.toUtf8(), &attachType, 0, 0, 0, &ns))
       
  1878                 return false;
       
  1879             if (ns || !attachType || !attachType->attachedPropertiesType())
       
  1880                 return false;
       
  1881 
       
  1882             wasAttachedObject = true;
       
  1883         } 
       
  1884 
       
  1885         if (ii == 0) {
       
  1886 
       
  1887             if (attachType) {
       
  1888                 Instr instr;
       
  1889                 instr.common.type = Instr::LoadScope;
       
  1890                 instr.load.index = 0;
       
  1891                 instr.load.reg = reg;
       
  1892                 bytecode << instr;
       
  1893 
       
  1894                 Instr attach;
       
  1895                 attach.common.type = Instr::LoadAttached;
       
  1896                 attach.attached.output = reg;
       
  1897                 attach.attached.reg = reg;
       
  1898                 attach.attached.index = attachType->index();
       
  1899                 attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
       
  1900                 bytecode << attach;
       
  1901 
       
  1902                 subscribeName << contextName();
       
  1903                 subscribeName << QLatin1String("$$$ATTACH_") + name;
       
  1904 
       
  1905                 absType = 0;
       
  1906                 type.metaObject = attachType->attachedPropertiesType();
       
  1907 
       
  1908                 continue;
       
  1909             } else if (ids.contains(name)) {
       
  1910                 QDeclarativeParser::Object *idObject = ids.value(name);
       
  1911                 absType = idObject;
       
  1912                 type.metaObject = absType->metaObject();
       
  1913 
       
  1914                 // We check if the id object is the root or 
       
  1915                 // scope object to avoid a subscription
       
  1916                 if (idObject == component) {
       
  1917                     Instr instr;
       
  1918                     instr.common.type = Instr::LoadRoot;
       
  1919                     instr.load.index = 0;
       
  1920                     instr.load.reg = reg;
       
  1921                     bytecode << instr;
       
  1922                 } else if (idObject == context) {
       
  1923                     Instr instr;
       
  1924                     instr.common.type = Instr::LoadScope;
       
  1925                     instr.load.index = 0;
       
  1926                     instr.load.reg = reg;
       
  1927                     bytecode << instr;
       
  1928                 } else {
       
  1929                     Instr instr;
       
  1930                     instr.common.type = Instr::LoadId;
       
  1931                     instr.load.index = idObject->idIndex;
       
  1932                     instr.load.reg = reg;
       
  1933                     bytecode << instr;
       
  1934 
       
  1935                     subscribeName << QLatin1String("$$$ID_") + name;
       
  1936 
       
  1937                     if (subscription(subscribeName, &type)) {
       
  1938                         Instr sub;
       
  1939                         sub.common.type = Instr::SubscribeId;
       
  1940                         sub.subscribe.offset = subscriptionIndex(subscribeName);
       
  1941                         sub.subscribe.reg = reg;
       
  1942                         sub.subscribe.index = instr.load.index;
       
  1943                         bytecode << sub;
       
  1944                     }
       
  1945                 }
       
  1946 
       
  1947             } else {
       
  1948 
       
  1949                 QByteArray utf8Name = name.toUtf8();
       
  1950                 const char *cname = utf8Name.constData();
       
  1951 
       
  1952                 int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
       
  1953                 int d1Idx = -1;
       
  1954                 if (d0Idx == -1)
       
  1955                     d1Idx = component->metaObject()->indexOfProperty(cname);
       
  1956 
       
  1957                 if (d0Idx != -1) {
       
  1958                     Instr instr;
       
  1959                     instr.common.type = Instr::LoadScope;
       
  1960                     instr.load.index = 0;
       
  1961                     instr.load.reg = reg;
       
  1962                     bytecode << instr;
       
  1963 
       
  1964                     subscribeName << contextName();
       
  1965                     subscribeName << name;
       
  1966 
       
  1967                     if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
       
  1968                         return false;
       
  1969                 } else if(d1Idx != -1) {
       
  1970                     Instr instr;
       
  1971                     instr.common.type = Instr::LoadRoot;
       
  1972                     instr.load.index = 0;
       
  1973                     instr.load.reg = reg;
       
  1974                     bytecode << instr;
       
  1975 
       
  1976                     subscribeName << QLatin1String("$$$ROOT");
       
  1977                     subscribeName << name;
       
  1978 
       
  1979                     if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
       
  1980                         return false;
       
  1981                 } else if (qmlExperimental()) {
       
  1982                     Instr find;
       
  1983                     if (nameParts.count() == 1)
       
  1984                         find.common.type = Instr::FindGenericTerminal;
       
  1985                     else
       
  1986                         find.common.type = Instr::FindGeneric;
       
  1987 
       
  1988                     find.find.reg = reg;
       
  1989                     find.find.src = -1;
       
  1990                     find.find.name = registerString(name);
       
  1991                     find.find.exceptionId = exceptionId(nameNodes.at(ii));
       
  1992 
       
  1993                     subscribeName << QString(QLatin1String("$$$Generic_") + name);
       
  1994                     if (subscription(subscribeName, &type)) 
       
  1995                         find.find.subscribeIndex = subscriptionIndex(subscribeName);
       
  1996                     else
       
  1997                         find.find.subscribeIndex = -1;
       
  1998 
       
  1999                     bytecode << find;
       
  2000                     type.unknownType = true;
       
  2001                 } 
       
  2002 
       
  2003                 if (!type.unknownType && type.type == -1)
       
  2004                     return false; // Couldn't fetch that type
       
  2005             } 
       
  2006 
       
  2007         } else {
       
  2008 
       
  2009             if (attachType) {
       
  2010                 Instr attach;
       
  2011                 attach.common.type = Instr::LoadAttached;
       
  2012                 attach.attached.output = reg;
       
  2013                 attach.attached.reg = reg;
       
  2014                 attach.attached.index = attachType->index();
       
  2015                 bytecode << attach;
       
  2016 
       
  2017                 absType = 0;
       
  2018                 type.metaObject = attachType->attachedPropertiesType();
       
  2019 
       
  2020                 subscribeName << QLatin1String("$$$ATTACH_") + name;
       
  2021                 continue;
       
  2022             }
       
  2023 
       
  2024             const QMetaObject *mo = 0;
       
  2025             if (absType)
       
  2026                 mo = absType->metaObject();
       
  2027             else if (type.metaObject)
       
  2028                 mo = type.metaObject;
       
  2029 
       
  2030             QByteArray utf8Name = name.toUtf8();
       
  2031             const char *cname = utf8Name.constData();
       
  2032             int idx = mo?mo->indexOfProperty(cname):-1;
       
  2033             if (absType && idx == -1)
       
  2034                 return false;
       
  2035 
       
  2036             subscribeName << name;
       
  2037 
       
  2038             if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
       
  2039                 absType = 0; 
       
  2040                 if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
       
  2041                     return false;
       
  2042             } else {
       
  2043 
       
  2044                 Instr prop;
       
  2045                 if (ii == nameParts.count() -1 ) 
       
  2046                     prop.common.type = Instr::FindPropertyTerminal;
       
  2047                 else
       
  2048                     prop.common.type = Instr::FindProperty;
       
  2049 
       
  2050                 prop.find.reg = reg;
       
  2051                 prop.find.src = reg;
       
  2052                 prop.find.name = registerString(name);
       
  2053                 prop.find.exceptionId = exceptionId(nameNodes.at(ii));
       
  2054 
       
  2055                 if (subscription(subscribeName, &type))
       
  2056                     prop.find.subscribeIndex = subscriptionIndex(subscribeName);
       
  2057                 else
       
  2058                     prop.find.subscribeIndex = -1;
       
  2059 
       
  2060                 type.unknownType = true;
       
  2061                 type.metaObject = 0;
       
  2062                 type.type = -1;
       
  2063                 type.reg = reg;
       
  2064                 bytecode << prop;
       
  2065             }
       
  2066         }
       
  2067 
       
  2068         wasAttachedObject = false;
       
  2069     }
       
  2070 
       
  2071     return true;
       
  2072 }
       
  2073 
       
  2074 bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
       
  2075 {
       
  2076     if (node->kind != AST::Node::Kind_BinaryExpression)
       
  2077         return false;
       
  2078 
       
  2079     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
       
  2080     if (expression->op == QSOperator::Add ||
       
  2081         expression->op == QSOperator::Sub)
       
  2082         return true;
       
  2083     else
       
  2084         return false;
       
  2085 }
       
  2086 
       
  2087 bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
       
  2088 {
       
  2089     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
       
  2090 
       
  2091     type.reg = acquireReg();
       
  2092     if (type.reg == -1)
       
  2093         return false;
       
  2094 
       
  2095     Result lhs;
       
  2096     Result rhs;
       
  2097 
       
  2098     if (!parseExpression(expression->left, lhs)) return false;
       
  2099     if (!parseExpression(expression->right, rhs)) return false;
       
  2100 
       
  2101     if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
       
  2102         (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
       
  2103         return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
       
  2104     else if(expression->op == QSOperator::Sub)
       
  2105         return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
       
  2106     else if ((lhs.type == QMetaType::QString || lhs.unknownType) && 
       
  2107              (rhs.type == QMetaType::QString || rhs.unknownType) && 
       
  2108              (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
       
  2109         return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
       
  2110     else
       
  2111         return false;
       
  2112 }
       
  2113 
       
  2114 bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
       
  2115 {
       
  2116     bool nativeReal = rhs.type == QMetaType::QReal ||
       
  2117                       lhs.type == QMetaType::QReal ||
       
  2118                       lhs.unknownType ||
       
  2119                       rhs.unknownType;
       
  2120 
       
  2121     if (nativeReal && lhs.type == QMetaType::Int) {
       
  2122         Instr convert;
       
  2123         convert.common.type = Instr::ConvertIntToReal;
       
  2124         convert.unaryop.output = lhs.reg;
       
  2125         convert.unaryop.src = lhs.reg;
       
  2126         bytecode << convert;
       
  2127     }
       
  2128 
       
  2129     if (nativeReal && rhs.type == QMetaType::Int) {
       
  2130         Instr convert;
       
  2131         convert.common.type = Instr::ConvertIntToReal;
       
  2132         convert.unaryop.output = rhs.reg;
       
  2133         convert.unaryop.src = rhs.reg;
       
  2134         bytecode << convert;
       
  2135     }
       
  2136 
       
  2137     int lhsTmp = -1;
       
  2138     int rhsTmp = -1;
       
  2139 
       
  2140     if (lhs.unknownType) {
       
  2141         if (!qmlExperimental())
       
  2142             return false;
       
  2143 
       
  2144         lhsTmp = acquireReg();
       
  2145         if (lhsTmp == -1)
       
  2146             return false;
       
  2147 
       
  2148         Instr conv;
       
  2149         conv.common.type = Instr::ConvertGenericToReal;
       
  2150         conv.unaryop.output = lhsTmp;
       
  2151         conv.unaryop.src = lhs.reg;
       
  2152         bytecode << conv;
       
  2153     }
       
  2154 
       
  2155     if (rhs.unknownType) {
       
  2156         if (!qmlExperimental())
       
  2157             return false;
       
  2158 
       
  2159         rhsTmp = acquireReg();
       
  2160         if (rhsTmp == -1)
       
  2161             return false;
       
  2162 
       
  2163         Instr conv;
       
  2164         conv.common.type = Instr::ConvertGenericToReal;
       
  2165         conv.unaryop.output = rhsTmp;
       
  2166         conv.unaryop.src = rhs.reg;
       
  2167         bytecode << conv;
       
  2168     }
       
  2169 
       
  2170     Instr arith;
       
  2171     if (op == QSOperator::Add) {
       
  2172         arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
       
  2173     } else if (op == QSOperator::Sub) {
       
  2174         arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
       
  2175     } else {
       
  2176         qFatal("Unsupported arithmetic operator");
       
  2177     }
       
  2178 
       
  2179     arith.binaryop.output = type.reg;
       
  2180     arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
       
  2181     arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
       
  2182     bytecode << arith;
       
  2183 
       
  2184     type.metaObject = 0;
       
  2185     type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
       
  2186     type.subscriptionSet.unite(lhs.subscriptionSet);
       
  2187     type.subscriptionSet.unite(rhs.subscriptionSet);
       
  2188 
       
  2189     if (lhsTmp != -1) releaseReg(lhsTmp);
       
  2190     if (rhsTmp != -1) releaseReg(rhsTmp);
       
  2191     releaseReg(lhs.reg);
       
  2192     releaseReg(rhs.reg);
       
  2193 
       
  2194     return true;
       
  2195 }
       
  2196 
       
  2197 bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
       
  2198 {
       
  2199     if (op != QSOperator::Add)
       
  2200         return false;
       
  2201 
       
  2202     int lhsTmp = -1;
       
  2203     int rhsTmp = -1;
       
  2204 
       
  2205     if (lhs.unknownType) {
       
  2206         if (!qmlExperimental())
       
  2207             return false;
       
  2208 
       
  2209         lhsTmp = acquireReg(Instr::CleanupString);
       
  2210         if (lhsTmp == -1)
       
  2211             return false;
       
  2212 
       
  2213         Instr convert;
       
  2214         convert.common.type = Instr::ConvertGenericToString;
       
  2215         convert.unaryop.output = lhsTmp;
       
  2216         convert.unaryop.src = lhs.reg;
       
  2217         bytecode << convert;
       
  2218     }
       
  2219 
       
  2220     if (rhs.unknownType) {
       
  2221         if (!qmlExperimental())
       
  2222             return false;
       
  2223 
       
  2224         rhsTmp = acquireReg(Instr::CleanupString);
       
  2225         if (rhsTmp == -1)
       
  2226             return false;
       
  2227 
       
  2228         Instr convert;
       
  2229         convert.common.type = Instr::ConvertGenericToString;
       
  2230         convert.unaryop.output = rhsTmp;
       
  2231         convert.unaryop.src = rhs.reg;
       
  2232         bytecode << convert;
       
  2233     }
       
  2234 
       
  2235     type.reg = acquireReg(Instr::CleanupString);
       
  2236     if (type.reg == -1)
       
  2237         return false;
       
  2238 
       
  2239     type.type = QMetaType::QString;
       
  2240 
       
  2241     Instr add;
       
  2242     add.common.type = Instr::AddString;
       
  2243     add.binaryop.output = type.reg;
       
  2244     add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
       
  2245     add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
       
  2246     bytecode << add;
       
  2247 
       
  2248     if (lhsTmp != -1) releaseReg(lhsTmp);
       
  2249     if (rhsTmp != -1) releaseReg(rhsTmp);
       
  2250 
       
  2251     return true;
       
  2252 }
       
  2253 
       
  2254 bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
       
  2255 {
       
  2256     if (node->kind != AST::Node::Kind_BinaryExpression)
       
  2257         return false;
       
  2258 
       
  2259     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
       
  2260     if (expression->op == QSOperator::Gt ||
       
  2261         expression->op == QSOperator::Equal ||
       
  2262         expression->op == QSOperator::NotEqual)
       
  2263         return true;
       
  2264     else
       
  2265         return false;
       
  2266 }
       
  2267 
       
  2268 bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
       
  2269 {
       
  2270     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
       
  2271 
       
  2272     Result lhs;
       
  2273     Result rhs;
       
  2274 
       
  2275     if (!parseExpression(expression->left, lhs)) return false;
       
  2276     if (!parseExpression(expression->right, rhs)) return false;
       
  2277 
       
  2278     type.reg = acquireReg();
       
  2279     if (type.reg == -1)
       
  2280         return false;
       
  2281 
       
  2282     type.metaObject = 0;
       
  2283     type.type = QVariant::Bool;
       
  2284 
       
  2285     if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
       
  2286 
       
  2287         Instr op;
       
  2288         if (expression->op == QSOperator::Gt)
       
  2289             op.common.type = Instr::GreaterThanReal;
       
  2290         else if (expression->op == QSOperator::Equal)
       
  2291             op.common.type = Instr::CompareReal;
       
  2292         else if (expression->op == QSOperator::NotEqual)
       
  2293             op.common.type = Instr::NotCompareReal;
       
  2294         else
       
  2295             return false;
       
  2296         op.binaryop.output = type.reg;
       
  2297         op.binaryop.src1 = lhs.reg;
       
  2298         op.binaryop.src2 = rhs.reg;
       
  2299         bytecode << op;
       
  2300 
       
  2301 
       
  2302     } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
       
  2303 
       
  2304         Instr op;
       
  2305         if (expression->op == QSOperator::Equal)
       
  2306             op.common.type = Instr::CompareString;
       
  2307         else if (expression->op == QSOperator::NotEqual)
       
  2308             op.common.type = Instr::NotCompareString;
       
  2309         else
       
  2310             return false;
       
  2311         op.binaryop.output = type.reg;
       
  2312         op.binaryop.src1 = lhs.reg;
       
  2313         op.binaryop.src2 = rhs.reg;
       
  2314         bytecode << op;
       
  2315 
       
  2316     } else {
       
  2317         return false;
       
  2318     }
       
  2319 
       
  2320     releaseReg(lhs.reg);
       
  2321     releaseReg(rhs.reg);
       
  2322 
       
  2323     return true;
       
  2324 }
       
  2325 
       
  2326 bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
       
  2327 {
       
  2328     return (node->kind == AST::Node::Kind_ConditionalExpression);
       
  2329 }
       
  2330 
       
  2331 bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
       
  2332 {
       
  2333     AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
       
  2334 
       
  2335     AST::Node *test = expression->expression;
       
  2336     if (test->kind == AST::Node::Kind_NestedExpression)
       
  2337         test = static_cast<AST::NestedExpression*>(test)->expression;
       
  2338 
       
  2339     Result etype;
       
  2340     if (!parseExpression(test, etype)) return false;
       
  2341 
       
  2342     if (etype.type != QVariant::Bool) 
       
  2343         return false;
       
  2344 
       
  2345     Instr skip;
       
  2346     skip.common.type = Instr::Skip;
       
  2347     skip.skip.reg = etype.reg;
       
  2348     skip.skip.count = 0;
       
  2349     int skipIdx = bytecode.count();
       
  2350     bytecode << skip;
       
  2351 
       
  2352     // Release to allow reuse of reg
       
  2353     releaseReg(etype.reg);
       
  2354 
       
  2355     QSet<QString> preSubSet = subscriptionSet;
       
  2356 
       
  2357     // int preConditionalSubscriptions = subscriptionSet.count();
       
  2358 
       
  2359     Result ok;
       
  2360     if (!parseExpression(expression->ok, ok)) return false;
       
  2361     if (ok.unknownType) return false;
       
  2362 
       
  2363     int skipIdx2 = bytecode.count();
       
  2364     skip.skip.reg = -1;
       
  2365     bytecode << skip;
       
  2366 
       
  2367     // Release to allow reuse of reg
       
  2368     releaseReg(ok.reg);
       
  2369     bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
       
  2370 
       
  2371     subscriptionSet = preSubSet;
       
  2372 
       
  2373     Result ko;
       
  2374     if (!parseExpression(expression->ko, ko)) return false;
       
  2375     if (ko.unknownType) return false;
       
  2376 
       
  2377     // Release to allow reuse of reg
       
  2378     releaseReg(ko.reg);
       
  2379     bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
       
  2380 
       
  2381     if (ok != ko)
       
  2382         return false; // Must be same type and in same register
       
  2383 
       
  2384     subscriptionSet = preSubSet;
       
  2385 
       
  2386     if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
       
  2387         return false; // Conditionals cannot introduce new subscriptions
       
  2388 
       
  2389     type = ok;
       
  2390 
       
  2391     return true;
       
  2392 }
       
  2393 
       
  2394 bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
       
  2395 {
       
  2396     return node->kind == AST::Node::Kind_TrueLiteral ||
       
  2397            node->kind == AST::Node::Kind_FalseLiteral ||
       
  2398            node->kind == AST::Node::Kind_NumericLiteral ||
       
  2399            node->kind == AST::Node::Kind_StringLiteral;
       
  2400 }
       
  2401 
       
  2402 bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
       
  2403 {
       
  2404     type.metaObject = 0;
       
  2405     type.type = -1;
       
  2406     type.reg = acquireReg();
       
  2407     if (type.reg == -1)
       
  2408         return false;
       
  2409 
       
  2410     if (node->kind == AST::Node::Kind_TrueLiteral) {
       
  2411         type.type = QVariant::Bool;
       
  2412         Instr instr;
       
  2413         instr.common.type = Instr::Bool;
       
  2414         instr.bool_value.reg = type.reg;
       
  2415         instr.bool_value.value = true;
       
  2416         bytecode << instr;
       
  2417         return true;
       
  2418     } else if (node->kind == AST::Node::Kind_FalseLiteral) {
       
  2419         type.type = QVariant::Bool;
       
  2420         Instr instr;
       
  2421         instr.common.type = Instr::Bool;
       
  2422         instr.bool_value.reg = type.reg;
       
  2423         instr.bool_value.value = false;
       
  2424         bytecode << instr;
       
  2425         return true;
       
  2426     } else if (node->kind == AST::Node::Kind_NumericLiteral) {
       
  2427         qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
       
  2428 
       
  2429         if (qreal(float(value)) != value)
       
  2430             return false;
       
  2431 
       
  2432         type.type = QMetaType::QReal;
       
  2433         Instr instr;
       
  2434         instr.common.type = Instr::Real;
       
  2435         instr.real_value.reg = type.reg;
       
  2436         instr.real_value.value = float(value);
       
  2437         bytecode << instr;
       
  2438         return true;
       
  2439     } else if (node->kind == AST::Node::Kind_StringLiteral) {
       
  2440         QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
       
  2441         type.type = QMetaType::QString;
       
  2442         type.reg = registerLiteralString(str);
       
  2443         return true;
       
  2444     } else {
       
  2445         return false;
       
  2446     }
       
  2447 }
       
  2448 
       
  2449 bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
       
  2450 {
       
  2451     return node->kind == AST::Node::Kind_CallExpression; 
       
  2452 }
       
  2453 
       
  2454 bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
       
  2455 {
       
  2456     AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
       
  2457 
       
  2458     QStringList name;
       
  2459     if (!buildName(name, expr->base))
       
  2460         return false;
       
  2461 
       
  2462     if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
       
  2463         return false;
       
  2464 
       
  2465     QString method = name.at(1);
       
  2466 
       
  2467     AST::ArgumentList *args = expr->arguments;
       
  2468     if (!args) return false;
       
  2469     AST::ExpressionNode *arg0 = args->expression;
       
  2470     args = args->next;
       
  2471     if (!args) return false;
       
  2472     AST::ExpressionNode *arg1 = args->expression;
       
  2473     if (args->next != 0) return false;
       
  2474     if (!arg0 || !arg1) return false;
       
  2475 
       
  2476     Result r0;
       
  2477     if (!parseExpression(arg0, r0)) return false;
       
  2478     Result r1;
       
  2479     if (!parseExpression(arg1, r1)) return false;
       
  2480 
       
  2481     if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
       
  2482         return false;
       
  2483 
       
  2484     Instr op;
       
  2485     if (method == QLatin1String("max")) {
       
  2486         op.common.type = Instr::MaxReal;
       
  2487     } else if (method == QLatin1String("min")) {
       
  2488         op.common.type = Instr::MinReal;
       
  2489     } else {
       
  2490         return false;
       
  2491     }
       
  2492     // We release early to reuse registers
       
  2493     releaseReg(r0.reg);
       
  2494     releaseReg(r1.reg);
       
  2495 
       
  2496     op.binaryop.output = acquireReg();
       
  2497     if (op.binaryop.output == -1)
       
  2498         return false;
       
  2499 
       
  2500     op.binaryop.src1 = r0.reg;
       
  2501     op.binaryop.src2 = r1.reg;
       
  2502     bytecode << op;
       
  2503 
       
  2504     result.type = QMetaType::QReal;
       
  2505     result.reg = op.binaryop.output;
       
  2506 
       
  2507     return true;
       
  2508 }
       
  2509 
       
  2510 bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
       
  2511                                        QDeclarativeJS::AST::Node *node,
       
  2512                                        QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
       
  2513 {
       
  2514     if (node->kind == AST::Node::Kind_IdentifierExpression) {
       
  2515         name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
       
  2516         if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
       
  2517     } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
       
  2518         AST::FieldMemberExpression *expr =
       
  2519             static_cast<AST::FieldMemberExpression *>(node);
       
  2520 
       
  2521         if (!buildName(name, expr->base, nodes))
       
  2522             return false;
       
  2523 
       
  2524         name << expr->name->asString();
       
  2525         if (nodes) *nodes << expr;
       
  2526     } else {
       
  2527         return false;
       
  2528     }
       
  2529 
       
  2530     return true;
       
  2531 }
       
  2532 
       
  2533 bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, 
       
  2534                                                int idx, const QStringList &subName, 
       
  2535                                                QDeclarativeJS::AST::ExpressionNode *node)
       
  2536 {
       
  2537     QMetaProperty prop = mo->property(idx);
       
  2538     rv.metaObject = 0;
       
  2539     rv.type = 0;
       
  2540 
       
  2541     int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
       
  2542 
       
  2543     Instr fetch;
       
  2544 
       
  2545     if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
       
  2546         fetch.common.type = Instr::FetchAndSubscribe;
       
  2547         fetch.fetchAndSubscribe.objectReg = reg;
       
  2548         fetch.fetchAndSubscribe.output = reg;
       
  2549         fetch.fetchAndSubscribe.function = fastFetchIndex;
       
  2550         fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
       
  2551         fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
       
  2552     } else {
       
  2553         if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
       
  2554             Instr sub;
       
  2555             sub.common.type = Instr::Subscribe;
       
  2556             sub.subscribe.offset = subscriptionIndex(subName);
       
  2557             sub.subscribe.reg = reg;
       
  2558             sub.subscribe.index = prop.notifySignalIndex();
       
  2559             bytecode << sub;
       
  2560         }
       
  2561 
       
  2562         fetch.common.type = Instr::Fetch;
       
  2563         fetch.fetch.objectReg = reg;
       
  2564         fetch.fetch.index = idx;
       
  2565         fetch.fetch.output = reg;
       
  2566         fetch.fetch.exceptionId = exceptionId(node);
       
  2567     }
       
  2568 
       
  2569     rv.type = prop.userType();
       
  2570     rv.metaObject = engine->metaObjectForType(rv.type);
       
  2571     rv.reg = reg;
       
  2572 
       
  2573     if (rv.type == QMetaType::QString) {
       
  2574         int tmp = acquireReg();
       
  2575         if (tmp == -1)
       
  2576             return false;
       
  2577         Instr copy;
       
  2578         copy.common.type = Instr::Copy;
       
  2579         copy.copy.reg = tmp;
       
  2580         copy.copy.src = reg;
       
  2581         bytecode << copy;
       
  2582         releaseReg(tmp);
       
  2583         fetch.fetch.objectReg = tmp;
       
  2584 
       
  2585         Instr setup;
       
  2586         setup.common.type = Instr::NewString;
       
  2587         setup.construct.reg = reg;
       
  2588         bytecode << setup;
       
  2589         registerCleanup(reg, Instr::CleanupString);
       
  2590     }
       
  2591 
       
  2592     bytecode << fetch;
       
  2593 
       
  2594     if (!rv.metaObject &&
       
  2595         rv.type != QMetaType::QReal &&
       
  2596         rv.type != QMetaType::Int &&
       
  2597         rv.type != QMetaType::Bool &&
       
  2598         rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
       
  2599         rv.type != QMetaType::QString) {
       
  2600         rv.metaObject = 0;
       
  2601         rv.type = 0;
       
  2602         return false; // Unsupported type (string not supported yet);
       
  2603     }
       
  2604 
       
  2605     return true;
       
  2606 }
       
  2607 
       
  2608 void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
       
  2609 {
       
  2610     registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
       
  2611 }
       
  2612 
       
  2613 int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
       
  2614 {
       
  2615     for (int ii = 0; ii < 32; ++ii) {
       
  2616         if (!(registers & (1 << ii))) {
       
  2617             registers |= (1 << ii);
       
  2618 
       
  2619             if (cleanup != Instr::Noop)
       
  2620                 registerCleanup(ii, cleanup, cleanupType);
       
  2621 
       
  2622             return ii;
       
  2623         }
       
  2624     }
       
  2625     return -1;
       
  2626 }
       
  2627 
       
  2628 void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
       
  2629 {
       
  2630     Q_ASSERT(reg >= 0 && reg <= 31);
       
  2631 
       
  2632     if (registerCleanups.contains(reg)) {
       
  2633         QPair<int, int> c = registerCleanups[reg];
       
  2634         registerCleanups.remove(reg);
       
  2635         Instr cleanup;
       
  2636         cleanup.common.type = (quint8)c.first;
       
  2637         cleanup.cleanup.reg = reg;
       
  2638         bytecode << cleanup;
       
  2639     }
       
  2640 
       
  2641     quint32 mask = 1 << reg;
       
  2642     registers &= ~mask;
       
  2643 }
       
  2644 
       
  2645 // Returns a reg
       
  2646 int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
       
  2647 {
       
  2648     QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
       
  2649     int offset = data.count();
       
  2650     data += strdata;
       
  2651 
       
  2652     int reg = acquireReg(Instr::CleanupString);
       
  2653     if (reg == -1)
       
  2654         return false;
       
  2655 
       
  2656     Instr string;
       
  2657     string.common.type = Instr::String;
       
  2658     string.string_value.reg = reg;
       
  2659     string.string_value.offset = offset;
       
  2660     string.string_value.length = str.length();
       
  2661     bytecode << string;
       
  2662 
       
  2663     return reg;
       
  2664 }
       
  2665 
       
  2666 // Returns an identifier offset
       
  2667 int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
       
  2668 {
       
  2669     Q_ASSERT(!string.isEmpty());
       
  2670 
       
  2671     QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
       
  2672 
       
  2673     if (iter == registeredStrings.end()) {
       
  2674         quint32 len = string.length();
       
  2675         QByteArray lendata((const char *)&len, sizeof(quint32));
       
  2676         QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
       
  2677         strdata.prepend(lendata);
       
  2678         int rv = data.count();
       
  2679         data += strdata;
       
  2680 
       
  2681         iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
       
  2682     } 
       
  2683 
       
  2684     Instr reg;
       
  2685     reg.common.type = Instr::InitString;
       
  2686     reg.initstring.offset = iter->first;
       
  2687     reg.initstring.dataIdx = iter->second;
       
  2688     bytecode << reg;
       
  2689     return reg.initstring.offset;
       
  2690 }
       
  2691 
       
  2692 bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
       
  2693 {
       
  2694     QString str = sub.join(QLatin1String("."));
       
  2695     result->subscriptionSet.insert(str);
       
  2696 
       
  2697     if (subscriptionSet.contains(str)) {
       
  2698         return false;
       
  2699     } else {
       
  2700         subscriptionSet.insert(str);
       
  2701         return true;
       
  2702     }
       
  2703 }
       
  2704 
       
  2705 int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
       
  2706 {
       
  2707     QString str = sub.join(QLatin1String("."));
       
  2708     QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
       
  2709     if (iter == subscriptionIds.end()) 
       
  2710         iter = subscriptionIds.insert(str, subscriptionIds.count());
       
  2711     usedSubscriptionIds.insert(*iter);
       
  2712     return *iter;
       
  2713 }
       
  2714 
       
  2715 /*
       
  2716     Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
       
  2717     rhs contains no subscriptions that aren't also in base or lhs.
       
  2718 */ 
       
  2719 bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, 
       
  2720                                              const QSet<QString> &lhs, 
       
  2721                                              const QSet<QString> &rhs)
       
  2722 {
       
  2723     QSet<QString> difflhs = lhs;
       
  2724     difflhs.subtract(rhs);
       
  2725     QSet<QString> diffrhs = rhs;
       
  2726     diffrhs.subtract(lhs);
       
  2727 
       
  2728     difflhs.unite(diffrhs);
       
  2729     difflhs.subtract(base);
       
  2730 
       
  2731     return difflhs.isEmpty();
       
  2732 }
       
  2733 
       
  2734 quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
       
  2735 {
       
  2736     quint8 rv = 0xFF;
       
  2737     if (n && exceptions.count() < 0xFF) {
       
  2738         rv = (quint8)exceptions.count();
       
  2739         QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
       
  2740         quint64 e = l.startLine;
       
  2741         e <<= 32;
       
  2742         e |= l.startColumn;
       
  2743         exceptions.append(e);
       
  2744     }
       
  2745     return rv;
       
  2746 }
       
  2747 
       
  2748 QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
       
  2749 : d(new QDeclarativeBindingCompilerPrivate)
       
  2750 {
       
  2751 }
       
  2752 
       
  2753 QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
       
  2754 {
       
  2755     delete d; d = 0;
       
  2756 }
       
  2757 
       
  2758 /* 
       
  2759 Returns true if any bindings were compiled.
       
  2760 */
       
  2761 bool QDeclarativeBindingCompiler::isValid() const
       
  2762 {
       
  2763     return !d->committed.bytecode.isEmpty();
       
  2764 }
       
  2765 
       
  2766 /* 
       
  2767 -1 on failure, otherwise the binding index to use.
       
  2768 */
       
  2769 int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
       
  2770 {
       
  2771     if (!expression.expression.asAST()) return false;
       
  2772 
       
  2773     if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
       
  2774         return -1;
       
  2775 
       
  2776     if (qmlDisableOptimizer())
       
  2777         return -1;
       
  2778 
       
  2779     d->context = expression.context;
       
  2780     d->component = expression.component;
       
  2781     d->destination = expression.property;
       
  2782     d->ids = expression.ids;
       
  2783     d->imports = expression.imports;
       
  2784     d->engine = engine;
       
  2785 
       
  2786     if (d->compile(expression.expression.asAST())) {
       
  2787         return d->commitCompile();
       
  2788     } else {
       
  2789         return -1;
       
  2790     }
       
  2791 }
       
  2792 
       
  2793 
       
  2794 QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
       
  2795 {
       
  2796     QHash<int, QList<int> > table;
       
  2797 
       
  2798     for (int ii = 0; ii < committed.count(); ++ii) {
       
  2799         const QSet<int> &deps = committed.dependencies.at(ii);
       
  2800         for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter) 
       
  2801             table[*iter].append(ii);
       
  2802     }
       
  2803 
       
  2804     QVector<quint32> header;
       
  2805     QVector<quint32> data;
       
  2806     for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
       
  2807         header.append(committed.subscriptionIds.count() + data.count());
       
  2808         const QList<int> &bindings = table[ii];
       
  2809         data.append(bindings.count());
       
  2810         for (int jj = 0; jj < bindings.count(); ++jj)
       
  2811             data.append(bindings.at(jj));
       
  2812     }
       
  2813     header << data;
       
  2814 
       
  2815     return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
       
  2816 }
       
  2817 
       
  2818 QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
       
  2819 {
       
  2820     QByteArray rv;
       
  2821     rv.resize(committed.exceptions.count() * sizeof(quint64));
       
  2822     ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
       
  2823     return rv;
       
  2824 }
       
  2825 
       
  2826 /* 
       
  2827 Returns the compiled program.
       
  2828 */
       
  2829 QByteArray QDeclarativeBindingCompiler::program() const
       
  2830 {
       
  2831     QByteArray programData;
       
  2832 
       
  2833     if (isValid()) {
       
  2834         Program prog;
       
  2835         prog.bindings = d->committed.count();
       
  2836 
       
  2837         QVector<Instr> bytecode;
       
  2838         Instr skip;
       
  2839         skip.common.type = Instr::Skip;
       
  2840         skip.skip.reg = -1;
       
  2841         for (int ii = 0; ii < d->committed.count(); ++ii) {
       
  2842             skip.skip.count = d->committed.count() - ii - 1;
       
  2843             skip.skip.count+= d->committed.offsets.at(ii);
       
  2844             bytecode << skip;
       
  2845         }
       
  2846         bytecode << d->committed.bytecode;
       
  2847 
       
  2848         QByteArray data = d->committed.data;
       
  2849         while (data.count() % 4) data.append('\0');
       
  2850         prog.signalTableOffset = data.count();
       
  2851         data += d->buildSignalTable();
       
  2852         while (data.count() % 4) data.append('\0');
       
  2853         prog.exceptionDataOffset = data.count();
       
  2854         data += d->buildExceptionData();
       
  2855 
       
  2856         prog.dataLength = 4 * ((data.size() + 3) / 4);
       
  2857         prog.subscriptions = d->committed.subscriptionIds.count();
       
  2858         prog.identifiers = d->committed.registeredStrings.count();
       
  2859         prog.instructionCount = bytecode.count();
       
  2860         prog.compiled = false;
       
  2861         int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
       
  2862         size += prog.dataLength;
       
  2863 
       
  2864         programData.resize(size);
       
  2865         memcpy(programData.data(), &prog, sizeof(Program));
       
  2866         if (prog.dataLength)
       
  2867             memcpy((char *)((Program *)programData.data())->data(), data.constData(), 
       
  2868                    data.size());
       
  2869         memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), 
       
  2870                bytecode.count() * sizeof(Instr));
       
  2871     } 
       
  2872 
       
  2873     return programData;
       
  2874 }
       
  2875 
       
  2876 
       
  2877 
       
  2878 QT_END_NAMESPACE