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