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