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