source: trunk/src/declarative/qml/qdeclarativecompiledbindings.cpp@ 928

Last change on this file since 928 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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