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