aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml')
-rw-r--r--src/declarative/qml/qdeclarative.h33
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp19
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings.cpp2906
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp3
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp149
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h5
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp39
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h1
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp84
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h11
-rw-r--r--src/declarative/qml/qdeclarativedirparser.cpp23
-rw-r--r--src/declarative/qml/qdeclarativedirparser_p.h16
-rw-r--r--src/declarative/qml/qdeclarativedom.cpp1835
-rw-r--r--src/declarative/qml/qdeclarativedom_p.h362
-rw-r--r--src/declarative/qml/qdeclarativedom_p_p.h157
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp135
-rw-r--r--src/declarative/qml/qdeclarativeengine.h3
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h25
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp7
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.cpp33
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.h5
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp208
-rw-r--r--src/declarative/qml/qdeclarativeimport_p.h6
-rw-r--r--src/declarative/qml/qdeclarativeinfo.cpp12
-rw-r--r--src/declarative/qml/qdeclarativeinstruction.cpp3
-rw-r--r--src/declarative/qml/qdeclarativeinstruction_p.h7
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp96
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h39
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp27
-rw-r--r--src/declarative/qml/qdeclarativeprivate.h17
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp2
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h21
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp193
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h163
-rw-r--r--src/declarative/qml/qdeclarativescriptparser.cpp47
-rw-r--r--src/declarative/qml/qdeclarativescriptparser_p.h2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp244
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h62
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp8
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h16
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp38
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp82
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h4
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp10
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp21
-rw-r--r--src/declarative/qml/qintrusivelist.cpp173
-rw-r--r--src/declarative/qml/qintrusivelist_p.h254
-rw-r--r--src/declarative/qml/qmetaobjectbuilder.cpp57
-rw-r--r--src/declarative/qml/qmetaobjectbuilder_p.h4
-rw-r--r--src/declarative/qml/qml.pri14
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp1530
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings_p.h92
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler.cpp1340
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p.h (renamed from src/declarative/qml/qdeclarativecompiledbindings_p.h)38
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p_p.h184
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction.cpp559
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction_p.h444
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir.cpp832
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir_p.h546
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder.cpp1315
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder_p.h242
-rw-r--r--src/declarative/qml/v4/qdeclarativev4program_p.h122
-rw-r--r--src/declarative/qml/v4/v4.pri17
64 files changed, 9329 insertions, 5614 deletions
diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h
index 5da7901528..9227260b64 100644
--- a/src/declarative/qml/qdeclarative.h
+++ b/src/declarative/qml/qdeclarative.h
@@ -53,6 +53,9 @@
QT_BEGIN_HEADER
+#define QML_VERSION 0x020000
+#define QML_VERSION_STR "2.0"
+
#define QML_DECLARE_TYPE(TYPE) \
Q_DECLARE_METATYPE(TYPE *) \
Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>)
@@ -392,6 +395,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
class QDeclarativeContext;
class QDeclarativeEngine;
+class QScriptValue;
+class QScriptEngine;
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *);
@@ -405,6 +410,34 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
}
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QScriptValue (*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ callback, 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QObject *(*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ 0, callback
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QObject)
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index a5bd604c53..3e93ce7266 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -357,13 +357,17 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
bool isUndefined = false;
QVariant value;
QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
- if (wasDeleted)
+
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
@@ -420,8 +424,10 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else if (d->property.object() &&
!QDeclarativePropertyPrivate::write(d->property, value, flags)) {
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
QUrl url = QUrl(d->url);
int line = d->line;
@@ -440,14 +446,21 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
QLatin1String(QMetaType::typeName(d->property.propertyType())));
}
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->error.isValid()) {
if (!d->addError(ep)) ep->warning(this->error());
} else {
d->removeError();
}
+
+ // at this point, the binding has been evaluated. If any scarce
+ // resources were copied during the evaluation of the binding,
+ // we need to release those copies.
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
d->updating = false;
diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp
deleted file mode 100644
index a6fcce4c99..0000000000
--- a/src/declarative/qml/qdeclarativecompiledbindings.cpp
+++ /dev/null
@@ -1,2906 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// #define COMPILEDBINDINGS_DEBUG
-// #define REGISTER_CLEANUP_DEBUG
-
-#include "private/qdeclarativecompiledbindings_p.h"
-
-#include <QtDeclarative/qdeclarativeinfo.h>
-#include <private/qdeclarativecontext_p.h>
-#include <private/qdeclarativejsast_p.h>
-#include <private/qdeclarativejsengine_p.h>
-#include <private/qdeclarativeexpression_p.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qnumeric.h>
-#include <private/qdeclarativeanchors_p_p.h>
-#include <private/qdeclarativeglobal_p.h>
-#include <private/qdeclarativefastproperties_p.h>
-#include <private/qdeclarativedebugtrace_p.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
-
-Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
-
-#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
-# define QML_THREADED_INTERPRETER
-#endif
-
-#define FOR_EACH_QML_INSTR(F) \
- F(Noop) /* Nop */ \
- F(BindingId) /* id */ \
- F(Subscribe) /* subscribe */ \
- F(SubscribeId) /* subscribe */ \
- F(FetchAndSubscribe) /* fetchAndSubscribe */ \
- F(LoadId) /* load */ \
- F(LoadScope) /* load */ \
- F(LoadRoot) /* load */ \
- F(LoadAttached) /* attached */ \
- F(ConvertIntToReal) /* unaryop */ \
- F(ConvertRealToInt) /* unaryop */ \
- F(Real) /* real_value */ \
- F(Int) /* int_value */ \
- F(Bool) /* bool_value */ \
- F(String) /* string_value */ \
- F(AddReal) /* binaryop */ \
- F(AddInt) /* binaryop */ \
- F(AddString) /* binaryop */ \
- F(MinusReal) /* binaryop */ \
- F(MinusInt) /* binaryop */ \
- F(CompareReal) /* binaryop */ \
- F(CompareString) /* binaryop */ \
- F(NotCompareReal) /* binaryop */ \
- F(NotCompareString) /* binaryop */ \
- F(GreaterThanReal) /* binaryop */ \
- F(MaxReal) /* binaryop */ \
- F(MinReal) /* binaryop */ \
- F(NewString) /* construct */ \
- F(NewUrl) /* construct */ \
- F(CleanupUrl) /* cleanup */ \
- F(CleanupString) /* cleanup */ \
- F(Copy) /* copy */ \
- F(Fetch) /* fetch */ \
- F(Store) /* store */ \
- F(Skip) /* skip */ \
- F(Done) /* done */ \
- /* Speculative property resolution */ \
- F(InitString) /* initstring */ \
- F(FindGeneric) /* find */ \
- F(FindGenericTerminal) /* find */ \
- F(FindProperty) /* find */ \
- F(FindPropertyTerminal) /* find */ \
- F(CleanupGeneric) /* cleanup */ \
- F(ConvertGenericToReal) /* unaryop */ \
- F(ConvertGenericToBool) /* unaryop */ \
- F(ConvertGenericToString) /* unaryop */ \
- F(ConvertGenericToUrl) /* unaryop */
-
-#define QML_INSTR_ENUM(I) I,
-#define QML_INSTR_ADDR(I) &&op_##I,
-
-#ifdef QML_THREADED_INTERPRETER
-# define QML_BEGIN_INSTR(I) op_##I:
-# define QML_END_INSTR(I) ++instr; goto *instr->common.code;
-# define QML_INSTR_HEADER void *code;
-#else
-# define QML_BEGIN_INSTR(I) case Instr::I:
-# define QML_END_INSTR(I) break;
-# define QML_INSTR_HEADER
-#endif
-
-
-using namespace QDeclarativeJS;
-
-namespace {
-// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
-struct Register {
- void setUndefined() { type = 0; }
- void setUnknownButDefined() { type = -1; }
- void setNaN() { setqreal(qSNaN()); }
- bool isUndefined() const { return type == 0; }
-
- void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
- QObject *getQObject() const { return *((QObject **)data); }
-
- void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
- qreal getqreal() const { return *((qreal *)data); }
-
- void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
- int getint() const { return *((int *)data); }
-
- void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
- bool getbool() const { return *((bool *)data); }
-
- QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
- QString *getstringptr() { return (QString *)typeDataPtr(); }
- QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
- const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
- const QString *getstringptr() const { return (QString *)typeDataPtr(); }
- const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
-
- void *typeDataPtr() { return (void *)&data; }
- void *typeMemory() { return (void *)data; }
- const void *typeDataPtr() const { return (void *)&data; }
- const void *typeMemory() const { return (void *)data; }
-
- int gettype() const { return type; }
- void settype(int t) { type = t; }
-
- int type; // Optional type
- void *data[2]; // Object stored here
-
-#ifdef REGISTER_CLEANUP_DEBUG
- Register() {
- type = 0;
- }
-
- ~Register() {
- int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 };
- bool found = (type == 0);
- int *ctype = allowedTypes;
- while (!found && *ctype) {
- found = (*ctype == type);
- ++ctype;
- }
- if (!found)
- qWarning("Register leaked of type %d", type);
- }
-#endif
-};
-}
-
-class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
-
-public:
- QDeclarativeCompiledBindingsPrivate();
- virtual ~QDeclarativeCompiledBindingsPrivate();
-
- struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
- Binding() : enabled(false), updating(0), property(0),
- scope(0), target(0), parent(0) {}
-
- // Inherited from QDeclarativeAbstractBinding
- virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void destroy();
-
- int index:30;
- bool enabled:1;
- bool updating:1;
- int property;
- QObject *scope;
- QObject *target;
-
- QDeclarativeCompiledBindingsPrivate *parent;
- };
-
- typedef QDeclarativeNotifierEndpoint Subscription;
- Subscription *subscriptions;
- QScriptDeclarativeClass::PersistentIdentifier *identifiers;
-
- void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
-
- const char *programData;
- Binding *m_bindings;
- quint32 *m_signalTable;
-
- static int methodCount;
-
- void init();
- void run(int instr, QDeclarativeContextData *context,
- QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
-
-
- inline void unsubscribe(int subIndex);
- inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
- inline void subscribe(QObject *o, int notifyIndex, int subIndex);
-
- QDeclarativePropertyCache::Data *findproperty(QObject *obj,
- const QScriptDeclarativeClass::Identifier &name,
- QDeclarativeEnginePrivate *enginePriv,
- QDeclarativePropertyCache::Data &local);
- bool findproperty(QObject *obj,
- Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
- void findgeneric(Register *output, // value output
- int subIdx, // Subscription index in config
- QDeclarativeContextData *context, // Context to search in
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
-};
-
-QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
-: subscriptions(0), identifiers(0)
-{
-}
-
-QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
-{
- delete [] subscriptions; subscriptions = 0;
- delete [] identifiers; identifiers = 0;
-}
-
-int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
-
-QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
-: QObject(*(new QDeclarativeCompiledBindingsPrivate))
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (d->methodCount == -1)
- d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
-
- d->programData = program;
-
- d->init();
-
- QDeclarativeAbstractExpression::setContext(context);
-}
-
-QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
-{
- Q_D(QDeclarativeCompiledBindings);
-
- delete [] d->m_bindings;
-}
-
-QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target,
- QObject *scope, int property)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
-
- rv->index = index;
- rv->property = property;
- rv->target = target;
- rv->scope = scope;
- rv->parent = d;
-
- addref(); // This is decremented in Binding::destroy()
-
- return rv;
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- if (enabled != e) {
- enabled = e;
-
- if (e) update(flags);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
-{
- QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
- parent->run(this, flags);
- QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
-{
- enabled = false;
- removeFromObject();
- clear();
- parent->q_func()->release();
-}
-
-int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
- id -= d->methodCount;
-
- quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
- quint32 count = *reeval;
- ++reeval;
- for (quint32 ii = 0; ii < count; ++ii) {
- d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
- }
- }
- return -1;
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- if (!binding->enabled)
- return;
-
- QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
- if (!context || !context->isValid())
- return;
-
- if (binding->updating) {
- QString name;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
- Q_ASSERT(vt);
-
- name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
- name.append(QLatin1String("."));
- name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
- } else {
- name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
- }
- qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
- return;
- }
-
- binding->updating = true;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
- Q_ASSERT(vt);
- vt->read(binding->target, binding->property & 0xFFFF);
-
- QObject *target = vt;
- run(binding->index, context, binding, binding->scope, target, flags);
-
- vt->write(binding->target, binding->property & 0xFFFF, flags);
- } else {
- run(binding->index, context, binding, binding->scope, binding->target, flags);
- }
- binding->updating = false;
-}
-
-namespace {
-// This structure is exactly 8-bytes in size
-struct Instr {
- enum {
- FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
- };
-
- union {
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[7];
- } common;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing;
- quint16 column;
- quint32 line;
- } id;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[3];
- quint16 subscriptions;
- quint16 identifiers;
- } init;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 offset;
- quint32 index;
- } subscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 index;
- } load;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 id;
- } attached;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 index;
- } store;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint16 subscription;
- quint16 function;
- } fetchAndSubscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint32 index;
- } fetch;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 packing[5];
- } copy;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } construct;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- float value;
- } real_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- int value;
- } int_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- bool value;
- quint8 packing[5];
- } bool_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 length;
- quint32 offset;
- } string_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src1;
- qint8 src2;
- quint8 packing[4];
- } binaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src;
- quint8 packing[5];
- } unaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 count;
- } skip;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 exceptionId;
- quint16 name;
- quint16 subscribeIndex;
- } find;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } cleanup;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[1];
- quint16 offset;
- quint32 dataIdx;
- } initstring;
- };
-};
-
-struct Program {
- quint32 bindings;
- quint32 dataLength;
- quint32 signalTableOffset;
- quint32 exceptionDataOffset;
- quint16 subscriptions;
- quint16 identifiers;
- quint16 instructionCount;
- quint16 compiled;
-
- const char *data() const { return ((const char *)this) + sizeof(Program); }
- const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
-};
-}
-
-struct QDeclarativeBindingCompilerPrivate
-{
- struct Result {
- Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
- bool operator==(const Result &o) const {
- return unknownType == o.unknownType &&
- metaObject == o.metaObject &&
- type == o.type &&
- reg == o.reg;
- }
- bool operator!=(const Result &o) const {
- return !(*this == o);
- }
- bool unknownType;
- const QMetaObject *metaObject;
- int type;
- int reg;
-
- QSet<QString> subscriptionSet;
- };
-
- QDeclarativeBindingCompilerPrivate() : registers(0) {}
-
- void resetInstanceState();
- int commitCompile();
-
- QDeclarativeParser::Object *context;
- QDeclarativeParser::Object *component;
- QDeclarativeParser::Property *destination;
- QHash<QString, QDeclarativeParser::Object *> ids;
- QDeclarativeImports imports;
- QDeclarativeEnginePrivate *engine;
-
- QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
-
- bool compile(QDeclarativeJS::AST::Node *);
-
- bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryName(QDeclarativeJS::AST::Node *);
- bool parseName(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryArith(QDeclarativeJS::AST::Node *);
- bool parseArith(QDeclarativeJS::AST::Node *, Result &);
- bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
- bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
-
- bool tryLogic(QDeclarativeJS::AST::Node *);
- bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConditional(QDeclarativeJS::AST::Node *);
- bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConstant(QDeclarativeJS::AST::Node *);
- bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryMethod(QDeclarativeJS::AST::Node *);
- bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
-
- bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
- bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
-
- quint32 registers;
- QHash<int, QPair<int, int> > registerCleanups;
- int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
- void registerCleanup(int reg, int cleanup, int cleanupType = 0);
- void releaseReg(int);
-
- int registerLiteralString(const QString &);
- int registerString(const QString &);
- QHash<QString, QPair<int, int> > registeredStrings;
- QByteArray data;
-
- bool subscription(const QStringList &, Result *);
- int subscriptionIndex(const QStringList &);
- bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
-
- quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
- QVector<quint64> exceptions;
-
- QSet<int> usedSubscriptionIds;
- QSet<QString> subscriptionSet;
- QHash<QString, int> subscriptionIds;
- QVector<Instr> bytecode;
-
- // Committed binding data
- struct {
- QList<int> offsets;
- QList<QSet<int> > dependencies;
-
- QVector<Instr> bytecode;
- QByteArray data;
- QHash<QString, int> subscriptionIds;
- QVector<quint64> exceptions;
-
- QHash<QString, QPair<int, int> > registeredStrings;
-
- int count() const { return offsets.count(); }
- } committed;
-
- QByteArray buildSignalTable() const;
- QByteArray buildExceptionData() const;
-};
-
-void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
-{
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->disconnect();
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- unsubscribe(subIndex);
-
- if (p->idValues[idIndex]) {
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + subIndex;
- sub->connect(&p->idValues[idIndex].bindings);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + subIndex;
- if (o)
- sub->connect(o, notifyIndex);
- else
- sub->disconnect();
-}
-
-// Conversion functions - these MUST match the QtScript expression path
-inline static qreal toReal(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return reg->getqreal();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toReal();
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-inline static QString toString(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return QString::number(reg->getqreal());
- } else if (type == QMetaType::Int) {
- return QString::number(reg->getint());
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toString();
- } else if (type == QMetaType::QString) {
- return *reg->getstringptr();
- } else {
- if (ok) *ok = false;
- return QString();
- }
-}
-
-inline static bool toBool(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::Bool) {
- return reg->getbool();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toBool();
- } else {
- if (ok) *ok = false;
- return false;
- }
-}
-
-inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- QUrl base;
- if (type == qMetaTypeId<QVariant>()) {
- QVariant *var = reg->getvariantptr();
- int vt = var->type();
- if (vt == QVariant::Url) {
- base = var->toUrl();
- } else if (vt == QVariant::ByteArray) {
- base = QUrl(QString::fromUtf8(var->toByteArray()));
- } else if (vt == QVariant::String) {
- base = QUrl(var->toString());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
- } else if (type == QMetaType::QString) {
- base = QUrl(*reg->getstringptr());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
-
- if (!base.isEmpty() && base.isRelative())
- return context->url.resolved(base);
- else
- return base;
-}
-
-static QObject *variantToQObject(const QVariant &value, bool *ok)
-{
- if (ok) *ok = true;
-
- if (value.userType() == QMetaType::QObjectStar) {
- return qvariant_cast<QObject*>(value);
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx, const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- if (!obj) {
- output->setUndefined();
- return false;
- }
-
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *property =
- QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
-
- if (property) {
- if (subIdx != -1)
- subscribe(obj, property->notifyIndex, subIdx);
-
- if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QObjectStar);
- } else if (property->propType == qMetaTypeId<QVariant>()) {
- QVariant v;
- void *args[] = { &v, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(v);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(v, &ok));
- if (!ok)
- output->setUndefined();
- else
- output->settype(QMetaType::QObjectStar);
- }
-
- } else {
- if (!isTerminal) {
- output->setUndefined();
- } else if (property->propType == QMetaType::QReal) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QReal);
- } else if (property->propType == QMetaType::Int) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Int);
- } else if (property->propType == QMetaType::Bool) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Bool);
- } else if (property->propType == QMetaType::QString) {
- new (output->typeDataPtr()) QString();
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QString);
- } else {
- new (output->typeDataPtr())
- QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
- output->settype(qMetaTypeId<QVariant>());
- }
- }
-
- return true;
- } else {
- output->setUndefined();
- return false;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output,
- int subIdx,
- QDeclarativeContextData *context,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
-
- while (context) {
-
- int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
-
-
- if (contextPropertyIndex != -1) {
-
- if (contextPropertyIndex < context->idValueCount) {
- output->setQObject(context->idValues[contextPropertyIndex]);
- output->settype(QMetaType::QObjectStar);
-
- if (subIdx != -1)
- subscribeId(context, contextPropertyIndex, subIdx);
-
- } else {
- QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
- const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(value);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(value, &ok));
- if (!ok) { output->setUndefined(); }
- else { output->settype(QMetaType::QObjectStar); }
- return;
- }
-
- if (subIdx != -1)
- subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
-
-
- }
-
- return;
- }
-
- if (QObject *root = context->contextObject) {
-
- if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
- return;
-
- }
-
- context = context->parent;
- }
-
- output->setUndefined();
-}
-
-void QDeclarativeCompiledBindingsPrivate::init()
-{
- Program *program = (Program *)programData;
- if (program->subscriptions)
- subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
- if (program->identifiers)
- identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
-
- m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
- m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
-}
-
-static void throwException(int id, QDeclarativeDelayedError *error,
- Program *program, QDeclarativeContextData *context,
- const QString &description = QString())
-{
- error->error.setUrl(context->url);
- if (description.isEmpty())
- error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
- else
- error->error.setDescription(description);
- if (id != 0xFF) {
- quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
- error->error.setLine((e >> 32) & 0xFFFFFFFF);
- error->error.setColumn(e & 0xFFFFFFFF);
- } else {
- error->error.setLine(-1);
- error->error.setColumn(-1);
- }
- if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
- QDeclarativeEnginePrivate::warning(context->engine, error->error);
-}
-
-static void dumpInstruction(const Instr *instr)
-{
- switch (instr->common.type) {
- case Instr::Noop:
- qWarning().nospace() << "\t" << "Noop";
- break;
- case Instr::BindingId:
- qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
- break;
- case Instr::Subscribe:
- qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::SubscribeId:
- qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::FetchAndSubscribe:
- qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
- break;
- case Instr::LoadId:
- qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadScope:
- qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadRoot:
- qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadAttached:
- qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
- break;
- case Instr::ConvertIntToReal:
- qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertRealToInt:
- qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::Real:
- qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
- break;
- case Instr::Int:
- qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
- break;
- case Instr::Bool:
- qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
- break;
- case Instr::String:
- qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
- break;
- case Instr::AddReal:
- qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddInt:
- qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddString:
- qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusReal:
- qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusInt:
- qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareReal:
- qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareString:
- qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareReal:
- qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareString:
- qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::GreaterThanReal:
- qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MaxReal:
- qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinReal:
- qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NewString:
- qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
- break;
- case Instr::NewUrl:
- qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
- break;
- case Instr::CleanupString:
- qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::CleanupUrl:
- qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::Fetch:
- qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
- break;
- case Instr::Store:
- qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
- break;
- case Instr::Copy:
- qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
- break;
- case Instr::Skip:
- qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
- break;
- case Instr::Done:
- qWarning().nospace() << "\t" << "Done";
- break;
- case Instr::InitString:
- qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
- break;
- case Instr::FindGeneric:
- qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindGenericTerminal:
- qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindProperty:
- qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::FindPropertyTerminal:
- qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::CleanupGeneric:
- qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::ConvertGenericToReal:
- qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToBool:
- qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToString:
- qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToUrl:
- qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- default:
- qWarning().nospace() << "\t" << "Unknown";
- break;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
- QDeclarativeContextData *context, QDeclarativeDelayedError *error,
- QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- error->removeError();
-
- Register registers[32];
-
- QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
- Program *program = (Program *)programData;
- const Instr *instr = program->instructions();
- instr += instrIndex;
- const char *data = program->data();
-
-#ifdef QML_THREADED_INTERPRETER
- static void *decode_instr[] = {
- FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
- };
-
- if (!program->compiled) {
- program->compiled = true;
- const Instr *inop = program->instructions();
- for (int i = 0; i < program->instructionCount; ++i) {
- Instr *op = (Instr *) inop++;
- op->common.code = decode_instr[op->common.type];
- }
- }
-
- goto *instr->common.code;
-#else
- // return;
-
-#ifdef COMPILEDBINDINGS_DEBUG
- qWarning().nospace() << "Begin binding run";
-#endif
-
- while (instr) {
- switch (instr->common.type) {
-
-#ifdef COMPILEDBINDINGS_DEBUG
- dumpInstruction(instr);
-#endif
-
-#endif
-
- QML_BEGIN_INSTR(Noop)
- QML_END_INSTR(Noop)
-
- QML_BEGIN_INSTR(BindingId)
- QML_END_INSTR(BindingId)
-
- QML_BEGIN_INSTR(SubscribeId)
- subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
- QML_END_INSTR(SubscribeId)
-
- QML_BEGIN_INSTR(Subscribe)
- {
- QObject *o = 0;
- const Register &object = registers[instr->subscribe.reg];
- if (!object.isUndefined()) o = object.getQObject();
- subscribe(o, instr->subscribe.index, instr->subscribe.offset);
- }
- QML_END_INSTR(Subscribe)
-
- QML_BEGIN_INSTR(FetchAndSubscribe)
- {
- const Register &input = registers[instr->fetchAndSubscribe.objectReg];
- Register &output = registers[instr->fetchAndSubscribe.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- int subIdx = instr->fetchAndSubscribe.subscription;
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
- if (subIdx != -1) {
- sub = (subscriptions + subIdx);
- sub->target = q;
- sub->targetMethod = methodCount + subIdx;
- }
- fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
- }
- }
- QML_END_INSTR(FetchAndSubscribe)
-
- QML_BEGIN_INSTR(LoadId)
- registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
- QML_END_INSTR(LoadId)
-
- QML_BEGIN_INSTR(LoadScope)
- registers[instr->load.reg].setQObject(scope);
- QML_END_INSTR(LoadScope)
-
- QML_BEGIN_INSTR(LoadRoot)
- registers[instr->load.reg].setQObject(context->contextObject);
- QML_END_INSTR(LoadRoot)
-
- QML_BEGIN_INSTR(LoadAttached)
- {
- const Register &input = registers[instr->attached.reg];
- Register &output = registers[instr->attached.output];
- if (input.isUndefined()) {
- throwException(instr->attached.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = registers[instr->attached.reg].getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- QObject *attached =
- qmlAttachedPropertiesObjectById(instr->attached.id,
- registers[instr->attached.reg].getQObject(),
- true);
- Q_ASSERT(attached);
- output.setQObject(attached);
- }
- }
- QML_END_INSTR(LoadAttached)
-
- QML_BEGIN_INSTR(ConvertIntToReal)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setqreal(qreal(input.getint()));
- }
- QML_END_INSTR(ConvertIntToReal)
-
- QML_BEGIN_INSTR(ConvertRealToInt)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setint(qRound(input.getqreal()));
- }
- QML_END_INSTR(ConvertRealToInt)
-
- QML_BEGIN_INSTR(Real)
- registers[instr->real_value.reg].setqreal(instr->real_value.value);
- QML_END_INSTR(Real)
-
- QML_BEGIN_INSTR(Int)
- registers[instr->int_value.reg].setint(instr->int_value.value);
- QML_END_INSTR(Int)
-
- QML_BEGIN_INSTR(Bool)
- registers[instr->bool_value.reg].setbool(instr->bool_value.value);
- QML_END_INSTR(Bool)
-
- QML_BEGIN_INSTR(String)
- {
- Register &output = registers[instr->string_value.reg];
- new (output.getstringptr())
- QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(String)
-
- QML_BEGIN_INSTR(AddReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() + rhs.getqreal());
- }
- QML_END_INSTR(AddReal)
-
- QML_BEGIN_INSTR(AddInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() + rhs.getint());
- }
- QML_END_INSTR(AddInt)
-
- QML_BEGIN_INSTR(AddString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
- else {
- if (lhs.isUndefined())
- new (output.getstringptr())
- QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
- else if (rhs.isUndefined())
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
- else
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() +
- *registers[instr->binaryop.src2].getstringptr());
- output.settype(QMetaType::QString);
- }
- }
- QML_END_INSTR(AddString)
-
- QML_BEGIN_INSTR(MinusReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() - rhs.getqreal());
- }
- QML_END_INSTR(MinusReal)
-
- QML_BEGIN_INSTR(MinusInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() - rhs.getint());
- }
- QML_END_INSTR(MinusInt)
-
- QML_BEGIN_INSTR(CompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(lhs.getqreal() == rhs.getqreal());
- }
- QML_END_INSTR(CompareReal)
-
- QML_BEGIN_INSTR(CompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
- }
- QML_END_INSTR(CompareString)
-
- QML_BEGIN_INSTR(NotCompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(lhs.getqreal() != rhs.getqreal());
- }
- QML_END_INSTR(NotCompareReal)
-
- QML_BEGIN_INSTR(NotCompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
- }
- QML_END_INSTR(NotCompareString)
-
- QML_BEGIN_INSTR(GreaterThanReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
- else output.setbool(lhs.getqreal() > rhs.getqreal());
- }
- QML_END_INSTR(GreaterThanReal)
-
- QML_BEGIN_INSTR(MaxReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MaxReal)
-
- QML_BEGIN_INSTR(MinReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MinReal)
-
- QML_BEGIN_INSTR(NewString)
- {
- Register &output = registers[instr->construct.reg];
- new (output.getstringptr()) QString;
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(NewString)
-
- QML_BEGIN_INSTR(NewUrl)
- {
- Register &output = registers[instr->construct.reg];
- new (output.geturlptr()) QUrl;
- output.settype(QMetaType::QUrl);
- }
- QML_END_INSTR(NewUrl)
-
- QML_BEGIN_INSTR(CleanupString)
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupString)
-
- QML_BEGIN_INSTR(CleanupUrl)
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupUrl)
-
- QML_BEGIN_INSTR(Fetch)
- {
- const Register &input = registers[instr->fetch.objectReg];
- Register &output = registers[instr->fetch.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetch.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- void *argv[] = { output.typeDataPtr(), 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
- }
- }
- QML_END_INSTR(Fetch)
-
- QML_BEGIN_INSTR(Store)
- {
- Register &data = registers[instr->store.reg];
- if (data.isUndefined()) {
- throwException(instr->store.exceptionId, error, program, context,
- QLatin1String("Unable to assign undefined value"));
- return;
- }
-
- int status = -1;
- void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
- QMetaObject::metacall(output, QMetaObject::WriteProperty,
- instr->store.index, argv);
- }
- QML_END_INSTR(Store)
-
- QML_BEGIN_INSTR(Copy)
- registers[instr->copy.reg] = registers[instr->copy.src];
- QML_END_INSTR(Copy)
-
- QML_BEGIN_INSTR(Skip)
- if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool())
- instr += instr->skip.count;
- QML_END_INSTR(Skip)
-
- QML_BEGIN_INSTR(Done)
- return;
- QML_END_INSTR(Done)
-
- QML_BEGIN_INSTR(InitString)
- if (!identifiers[instr->initstring.offset].identifier) {
- quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
- QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
-
- QString str = QString::fromRawData(strdata, len);
-
- identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
- }
- QML_END_INSTR(InitString)
-
- QML_BEGIN_INSTR(FindGenericTerminal)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGenericTerminal)
-
- QML_BEGIN_INSTR(FindGeneric)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGeneric)
-
- QML_BEGIN_INSTR(FindPropertyTerminal)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindPropertyTerminal)
-
- QML_BEGIN_INSTR(FindProperty)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindProperty)
-
- QML_BEGIN_INSTR(CleanupGeneric)
- {
- int type = registers[instr->cleanup.reg].gettype();
- if (type == qMetaTypeId<QVariant>()) {
- registers[instr->cleanup.reg].getvariantptr()->~QVariant();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QString) {
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QUrl) {
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- }
- }
- QML_END_INSTR(CleanupGeneric)
-
- QML_BEGIN_INSTR(ConvertGenericToReal)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setqreal(toReal(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToReal)
-
- QML_BEGIN_INSTR(ConvertGenericToBool)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setbool(toBool(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToBool)
-
- QML_BEGIN_INSTR(ConvertGenericToString)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QString str = toString(&input, input.gettype(), &ok);
- if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToString)
-
- QML_BEGIN_INSTR(ConvertGenericToUrl)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QUrl url = toUrl(&input, input.gettype(), context, &ok);
- if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToUrl)
-
-#ifdef QML_THREADED_INTERPRETER
- // nothing to do
-#else
- default:
- qFatal("EEK");
- break;
- } // switch
-
- ++instr;
- } // while
-#endif
-}
-
-void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
-{
- const Program *program = (const Program *)programData.constData();
-
- qWarning() << "Program.bindings:" << program->bindings;
- qWarning() << "Program.dataLength:" << program->dataLength;
- qWarning() << "Program.subscriptions:" << program->subscriptions;
- qWarning() << "Program.indentifiers:" << program->identifiers;
-
- int count = program->instructionCount;
- const Instr *instr = program->instructions();
-
- while (count--) {
-
- dumpInstruction(instr);
- ++instr;
- }
-}
-
-/*!
-Clear the state associated with attempting to compile a specific binding.
-This does not clear the global "committed binding" states.
-*/
-void QDeclarativeBindingCompilerPrivate::resetInstanceState()
-{
- registers = 0;
- registerCleanups.clear();
- data = committed.data;
- exceptions = committed.exceptions;
- usedSubscriptionIds.clear();
- subscriptionSet.clear();
- subscriptionIds = committed.subscriptionIds;
- registeredStrings = committed.registeredStrings;
- bytecode.clear();
-}
-
-/*!
-Mark the last compile as successful, and add it to the "committed data"
-section.
-
-Returns the index for the committed binding.
-*/
-int QDeclarativeBindingCompilerPrivate::commitCompile()
-{
- int rv = committed.count();
- committed.offsets << committed.bytecode.count();
- committed.dependencies << usedSubscriptionIds;
- committed.bytecode << bytecode;
- committed.data = data;
- committed.exceptions = exceptions;
- committed.subscriptionIds = subscriptionIds;
- committed.registeredStrings = registeredStrings;
- return rv;
-}
-
-bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
-{
- resetInstanceState();
-
- if (destination->type == -1)
- return false;
-
- if (bindingsDump()) {
- QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
- if (n) {
- Instr id;
- id.common.type = Instr::BindingId;
- id.id.column = n->firstSourceLocation().startColumn;
- id.id.line = n->firstSourceLocation().startLine;
- bytecode << id;
- }
- }
-
- Result type;
-
- if (!parseExpression(node, type))
- return false;
-
- if (subscriptionSet.count() > 0xFFFF ||
- registeredStrings.count() > 0xFFFF)
- return false;
-
- if (type.unknownType) {
- if (!qmlExperimental())
- return false;
-
- if (destination->type != QMetaType::QReal &&
- destination->type != QVariant::String &&
- destination->type != QMetaType::Bool &&
- destination->type != QVariant::Url)
- return false;
-
- int convertReg = acquireReg();
- if (convertReg == -1)
- return false;
-
- if (destination->type == QMetaType::QReal) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToReal;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::String) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QMetaType::Bool) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToBool;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::Url) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToUrl;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- }
-
- Instr cleanup;
- cleanup.common.type = Instr::CleanupGeneric;
- cleanup.cleanup.reg = type.reg;
- bytecode << cleanup;
-
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = convertReg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- if (destination->type == QVariant::String) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupString;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- } else if (destination->type == QVariant::Url) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupUrl;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- }
-
- releaseReg(convertReg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
-
- } else {
- // Can we store the final value?
- if (type.type == QVariant::Int &&
- destination->type == QMetaType::QReal) {
- Instr instr;
- instr.common.type = Instr::ConvertIntToReal;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QMetaType::QReal;
- } else if (type.type == QMetaType::QReal &&
- destination->type == QVariant::Int) {
- Instr instr;
- instr.common.type = Instr::ConvertRealToInt;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QVariant::Int;
- } else if (type.type == destination->type) {
- } else {
- const QMetaObject *from = type.metaObject;
- const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
-
- if (QDeclarativePropertyPrivate::canConvert(from, to))
- type.type = destination->type;
- }
-
- if (type.type == destination->type) {
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = type.reg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- releaseReg(type.reg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
- } else {
- return false;
- }
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
-{
- while (node->kind == AST::Node::Kind_NestedExpression)
- node = static_cast<AST::NestedExpression *>(node)->expression;
-
- if (tryArith(node)) {
- if (!parseArith(node, type)) return false;
- } else if (tryLogic(node)) {
- if (!parseLogic(node, type)) return false;
- } else if (tryConditional(node)) {
- if (!parseConditional(node, type)) return false;
- } else if (tryName(node)) {
- if (!parseName(node, type)) return false;
- } else if (tryConstant(node)) {
- if (!parseConstant(node, type)) return false;
- } else if (tryMethod(node)) {
- if (!parseMethod(node, type)) return false;
- } else {
- return false;
- }
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_IdentifierExpression ||
- node->kind == AST::Node::Kind_FieldMemberExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
-{
- QStringList nameParts;
- QList<AST::ExpressionNode *> nameNodes;
- if (!buildName(nameParts, node, &nameNodes))
- return false;
-
- int reg = acquireReg();
- if (reg == -1)
- return false;
- type.reg = reg;
-
- QDeclarativeParser::Object *absType = 0;
-
- QStringList subscribeName;
-
- bool wasAttachedObject = false;
-
- for (int ii = 0; ii < nameParts.count(); ++ii) {
- const QString &name = nameParts.at(ii);
-
- // We don't handle signal properties or attached properties
- if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
- name.at(2).isUpper())
- return false;
-
- QDeclarativeType *attachType = 0;
- if (name.at(0).isUpper()) {
- // Could be an attached property
- if (ii == nameParts.count() - 1)
- return false;
- if (nameParts.at(ii + 1).at(0).isUpper())
- return false;
-
- QDeclarativeImportedNamespace *ns = 0;
- if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
- return false;
- if (ns || !attachType || !attachType->attachedPropertiesType())
- return false;
-
- wasAttachedObject = true;
- }
-
- if (ii == 0) {
-
- if (attachType) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
- bytecode << attach;
-
- subscribeName << contextName();
- subscribeName << QLatin1String("$$$ATTACH_") + name;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- continue;
- } else if (ids.contains(name)) {
- QDeclarativeParser::Object *idObject = ids.value(name);
- absType = idObject;
- type.metaObject = absType->metaObject();
-
- // We check if the id object is the root or
- // scope object to avoid a subscription
- if (idObject == component) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else if (idObject == context) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else {
- Instr instr;
- instr.common.type = Instr::LoadId;
- instr.load.index = idObject->idIndex;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ID_") + name;
-
- if (subscription(subscribeName, &type)) {
- Instr sub;
- sub.common.type = Instr::SubscribeId;
- sub.subscribe.offset = subscriptionIndex(subscribeName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = instr.load.index;
- bytecode << sub;
- }
- }
-
- } else {
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
-
- int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
- int d1Idx = -1;
- if (d0Idx == -1)
- d1Idx = component->metaObject()->indexOfProperty(cname);
-
- if (d0Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << contextName();
- subscribeName << name;
-
- if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if(d1Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ROOT");
- subscribeName << name;
-
- if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if (qmlExperimental()) {
- Instr find;
- if (nameParts.count() == 1)
- find.common.type = Instr::FindGenericTerminal;
- else
- find.common.type = Instr::FindGeneric;
-
- find.find.reg = reg;
- find.find.src = -1;
- find.find.name = registerString(name);
- find.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- subscribeName << QString(QLatin1String("$$$Generic_") + name);
- if (subscription(subscribeName, &type))
- find.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- find.find.subscribeIndex = -1;
-
- bytecode << find;
- type.unknownType = true;
- }
-
- if (!type.unknownType && type.type == -1)
- return false; // Couldn't fetch that type
- }
-
- } else {
-
- if (attachType) {
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- bytecode << attach;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- subscribeName << QLatin1String("$$$ATTACH_") + name;
- continue;
- }
-
- const QMetaObject *mo = 0;
- if (absType)
- mo = absType->metaObject();
- else if (type.metaObject)
- mo = type.metaObject;
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
- int idx = mo?mo->indexOfProperty(cname):-1;
- if (absType && idx == -1)
- return false;
-
- subscribeName << name;
-
- if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
- absType = 0;
- if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else {
-
- Instr prop;
- if (ii == nameParts.count() -1 )
- prop.common.type = Instr::FindPropertyTerminal;
- else
- prop.common.type = Instr::FindProperty;
-
- prop.find.reg = reg;
- prop.find.src = reg;
- prop.find.name = registerString(name);
- prop.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- if (subscription(subscribeName, &type))
- prop.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- prop.find.subscribeIndex = -1;
-
- type.unknownType = true;
- type.metaObject = 0;
- type.type = -1;
- type.reg = reg;
- bytecode << prop;
- }
- }
-
- wasAttachedObject = false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Add ||
- expression->op == QSOperator::Sub)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
- (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if(expression->op == QSOperator::Sub)
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if ((lhs.type == QMetaType::QString || lhs.unknownType) &&
- (rhs.type == QMetaType::QString || rhs.unknownType) &&
- (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
- return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- bool nativeReal = rhs.type == QMetaType::QReal ||
- lhs.type == QMetaType::QReal ||
- lhs.unknownType ||
- rhs.unknownType;
-
- if (nativeReal && lhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = lhs.reg;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (nativeReal && rhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = rhs.reg;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg();
- if (lhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = lhsTmp;
- conv.unaryop.src = lhs.reg;
- bytecode << conv;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg();
- if (rhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = rhsTmp;
- conv.unaryop.src = rhs.reg;
- bytecode << conv;
- }
-
- Instr arith;
- if (op == QSOperator::Add) {
- arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
- } else if (op == QSOperator::Sub) {
- arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
- } else {
- qFatal("Unsupported arithmetic operator");
- }
-
- arith.binaryop.output = type.reg;
- arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << arith;
-
- type.metaObject = 0;
- type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
- type.subscriptionSet.unite(lhs.subscriptionSet);
- type.subscriptionSet.unite(rhs.subscriptionSet);
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- if (op != QSOperator::Add)
- return false;
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg(Instr::CleanupString);
- if (lhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = lhsTmp;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg(Instr::CleanupString);
- if (rhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = rhsTmp;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- type.reg = acquireReg(Instr::CleanupString);
- if (type.reg == -1)
- return false;
-
- type.type = QMetaType::QString;
-
- Instr add;
- add.common.type = Instr::AddString;
- add.binaryop.output = type.reg;
- add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << add;
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Gt ||
- expression->op == QSOperator::Equal ||
- expression->op == QSOperator::NotEqual)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- type.metaObject = 0;
- type.type = QVariant::Bool;
-
- if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
-
- Instr op;
- if (expression->op == QSOperator::Gt)
- op.common.type = Instr::GreaterThanReal;
- else if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareReal;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareReal;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
-
- } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
-
- Instr op;
- if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareString;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareString;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
- } else {
- return false;
- }
-
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
-{
- return (node->kind == AST::Node::Kind_ConditionalExpression);
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
-
- AST::Node *test = expression->expression;
- if (test->kind == AST::Node::Kind_NestedExpression)
- test = static_cast<AST::NestedExpression*>(test)->expression;
-
- Result etype;
- if (!parseExpression(test, etype)) return false;
-
- if (etype.type != QVariant::Bool)
- return false;
-
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = etype.reg;
- skip.skip.count = 0;
- int skipIdx = bytecode.count();
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(etype.reg);
-
- QSet<QString> preSubSet = subscriptionSet;
-
- // int preConditionalSubscriptions = subscriptionSet.count();
-
- Result ok;
- if (!parseExpression(expression->ok, ok)) return false;
- if (ok.unknownType) return false;
-
- int skipIdx2 = bytecode.count();
- skip.skip.reg = -1;
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(ok.reg);
- bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
-
- subscriptionSet = preSubSet;
-
- Result ko;
- if (!parseExpression(expression->ko, ko)) return false;
- if (ko.unknownType) return false;
-
- // Release to allow reuse of reg
- releaseReg(ko.reg);
- bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
-
- if (ok != ko)
- return false; // Must be same type and in same register
-
- subscriptionSet = preSubSet;
-
- if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
- return false; // Conditionals cannot introduce new subscriptions
-
- type = ok;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_TrueLiteral ||
- node->kind == AST::Node::Kind_FalseLiteral ||
- node->kind == AST::Node::Kind_NumericLiteral ||
- node->kind == AST::Node::Kind_StringLiteral;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
-{
- type.metaObject = 0;
- type.type = -1;
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- if (node->kind == AST::Node::Kind_TrueLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = true;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_FalseLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = false;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_NumericLiteral) {
- qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
-
- if (qreal(float(value)) != value)
- return false;
-
- type.type = QMetaType::QReal;
- Instr instr;
- instr.common.type = Instr::Real;
- instr.real_value.reg = type.reg;
- instr.real_value.value = float(value);
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_StringLiteral) {
- QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
- type.type = QMetaType::QString;
- type.reg = registerLiteralString(str);
- return true;
- } else {
- return false;
- }
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_CallExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
-{
- AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
-
- QStringList name;
- if (!buildName(name, expr->base))
- return false;
-
- if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
- return false;
-
- QString method = name.at(1);
-
- AST::ArgumentList *args = expr->arguments;
- if (!args) return false;
- AST::ExpressionNode *arg0 = args->expression;
- args = args->next;
- if (!args) return false;
- AST::ExpressionNode *arg1 = args->expression;
- if (args->next != 0) return false;
- if (!arg0 || !arg1) return false;
-
- Result r0;
- if (!parseExpression(arg0, r0)) return false;
- Result r1;
- if (!parseExpression(arg1, r1)) return false;
-
- if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
- return false;
-
- Instr op;
- if (method == QLatin1String("max")) {
- op.common.type = Instr::MaxReal;
- } else if (method == QLatin1String("min")) {
- op.common.type = Instr::MinReal;
- } else {
- return false;
- }
- // We release early to reuse registers
- releaseReg(r0.reg);
- releaseReg(r1.reg);
-
- op.binaryop.output = acquireReg();
- if (op.binaryop.output == -1)
- return false;
-
- op.binaryop.src1 = r0.reg;
- op.binaryop.src2 = r1.reg;
- bytecode << op;
-
- result.type = QMetaType::QReal;
- result.reg = op.binaryop.output;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
- QDeclarativeJS::AST::Node *node,
- QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
-{
- if (node->kind == AST::Node::Kind_IdentifierExpression) {
- name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
- if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
- } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
- AST::FieldMemberExpression *expr =
- static_cast<AST::FieldMemberExpression *>(node);
-
- if (!buildName(name, expr->base, nodes))
- return false;
-
- name << expr->name->asString();
- if (nodes) *nodes << expr;
- } else {
- return false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg,
- int idx, const QStringList &subName,
- QDeclarativeJS::AST::ExpressionNode *node)
-{
- QMetaProperty prop = mo->property(idx);
- rv.metaObject = 0;
- rv.type = 0;
-
- //XXX binding optimizer doesn't handle properties with a revision
- if (prop.revision() > 0)
- return false;
-
- int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
-
- Instr fetch;
-
- if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
- fetch.common.type = Instr::FetchAndSubscribe;
- fetch.fetchAndSubscribe.objectReg = reg;
- fetch.fetchAndSubscribe.output = reg;
- fetch.fetchAndSubscribe.function = fastFetchIndex;
- fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
- fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
- } else {
- if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
- Instr sub;
- sub.common.type = Instr::Subscribe;
- sub.subscribe.offset = subscriptionIndex(subName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = prop.notifySignalIndex();
- bytecode << sub;
- }
-
- fetch.common.type = Instr::Fetch;
- fetch.fetch.objectReg = reg;
- fetch.fetch.index = idx;
- fetch.fetch.output = reg;
- fetch.fetch.exceptionId = exceptionId(node);
- }
-
- rv.type = prop.userType();
- rv.metaObject = engine->metaObjectForType(rv.type);
- rv.reg = reg;
-
- if (rv.type == QMetaType::QString) {
- int tmp = acquireReg();
- if (tmp == -1)
- return false;
- Instr copy;
- copy.common.type = Instr::Copy;
- copy.copy.reg = tmp;
- copy.copy.src = reg;
- bytecode << copy;
- releaseReg(tmp);
- fetch.fetch.objectReg = tmp;
-
- Instr setup;
- setup.common.type = Instr::NewString;
- setup.construct.reg = reg;
- bytecode << setup;
- registerCleanup(reg, Instr::CleanupString);
- }
-
- bytecode << fetch;
-
- if (!rv.metaObject &&
- rv.type != QMetaType::QReal &&
- rv.type != QMetaType::Int &&
- rv.type != QMetaType::Bool &&
- rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
- rv.type != QMetaType::QString) {
- rv.metaObject = 0;
- rv.type = 0;
- return false; // Unsupported type (string not supported yet);
- }
-
- return true;
-}
-
-void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
-{
- registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
-}
-
-int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
-{
- for (int ii = 0; ii < 32; ++ii) {
- if (!(registers & (1 << ii))) {
- registers |= (1 << ii);
-
- if (cleanup != Instr::Noop)
- registerCleanup(ii, cleanup, cleanupType);
-
- return ii;
- }
- }
- return -1;
-}
-
-void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
-{
- Q_ASSERT(reg >= 0 && reg <= 31);
-
- if (registerCleanups.contains(reg)) {
- QPair<int, int> c = registerCleanups[reg];
- registerCleanups.remove(reg);
- Instr cleanup;
- cleanup.common.type = (quint8)c.first;
- cleanup.cleanup.reg = reg;
- bytecode << cleanup;
- }
-
- quint32 mask = 1 << reg;
- registers &= ~mask;
-}
-
-// Returns a reg
-int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
-{
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- int reg = acquireReg(Instr::CleanupString);
- if (reg == -1)
- return false;
-
- Instr string;
- string.common.type = Instr::String;
- string.string_value.reg = reg;
- string.string_value.offset = offset;
- string.string_value.length = str.length();
- bytecode << string;
-
- return reg;
-}
-
-// Returns an identifier offset
-int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
-{
- Q_ASSERT(!string.isEmpty());
-
- QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
-
- if (iter == registeredStrings.end()) {
- quint32 len = string.length();
- QByteArray lendata((const char *)&len, sizeof(quint32));
- QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
- strdata.prepend(lendata);
- int rv = data.count();
- data += strdata;
-
- iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
- }
-
- Instr reg;
- reg.common.type = Instr::InitString;
- reg.initstring.offset = iter->first;
- reg.initstring.dataIdx = iter->second;
- bytecode << reg;
- return reg.initstring.offset;
-}
-
-bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
-{
- QString str = sub.join(QLatin1String("."));
- result->subscriptionSet.insert(str);
-
- if (subscriptionSet.contains(str)) {
- return false;
- } else {
- subscriptionSet.insert(str);
- return true;
- }
-}
-
-int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
- QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
- if (iter == subscriptionIds.end())
- iter = subscriptionIds.insert(str, subscriptionIds.count());
- usedSubscriptionIds.insert(*iter);
- return *iter;
-}
-
-/*
- Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
- rhs contains no subscriptions that aren't also in base or lhs.
-*/
-bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
- const QSet<QString> &lhs,
- const QSet<QString> &rhs)
-{
- QSet<QString> difflhs = lhs;
- difflhs.subtract(rhs);
- QSet<QString> diffrhs = rhs;
- diffrhs.subtract(lhs);
-
- difflhs.unite(diffrhs);
- difflhs.subtract(base);
-
- return difflhs.isEmpty();
-}
-
-quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
-{
- quint8 rv = 0xFF;
- if (n && exceptions.count() < 0xFF) {
- rv = (quint8)exceptions.count();
- QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
- quint64 e = l.startLine;
- e <<= 32;
- e |= l.startColumn;
- exceptions.append(e);
- }
- return rv;
-}
-
-QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
-: d(new QDeclarativeBindingCompilerPrivate)
-{
-}
-
-QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
-{
- delete d; d = 0;
-}
-
-/*
-Returns true if any bindings were compiled.
-*/
-bool QDeclarativeBindingCompiler::isValid() const
-{
- return !d->committed.bytecode.isEmpty();
-}
-
-/*
--1 on failure, otherwise the binding index to use.
-*/
-int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
-{
- if (!expression.expression.asAST()) return false;
-
- if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
- return -1;
-
- if (qmlDisableOptimizer())
- return -1;
-
- d->context = expression.context;
- d->component = expression.component;
- d->destination = expression.property;
- d->ids = expression.ids;
- d->imports = expression.imports;
- d->engine = engine;
-
- if (d->compile(expression.expression.asAST())) {
- return d->commitCompile();
- } else {
- return -1;
- }
-}
-
-
-QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
-{
- QHash<int, QList<int> > table;
-
- for (int ii = 0; ii < committed.count(); ++ii) {
- const QSet<int> &deps = committed.dependencies.at(ii);
- for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
- table[*iter].append(ii);
- }
-
- QVector<quint32> header;
- QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
- header.append(committed.subscriptionIds.count() + data.count());
- const QList<int> &bindings = table[ii];
- data.append(bindings.count());
- for (int jj = 0; jj < bindings.count(); ++jj)
- data.append(bindings.at(jj));
- }
- header << data;
-
- return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
-}
-
-QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
-{
- QByteArray rv;
- rv.resize(committed.exceptions.count() * sizeof(quint64));
- ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
- return rv;
-}
-
-/*
-Returns the compiled program.
-*/
-QByteArray QDeclarativeBindingCompiler::program() const
-{
- QByteArray programData;
-
- if (isValid()) {
- Program prog;
- prog.bindings = d->committed.count();
-
- QVector<Instr> bytecode;
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = -1;
- for (int ii = 0; ii < d->committed.count(); ++ii) {
- skip.skip.count = d->committed.count() - ii - 1;
- skip.skip.count+= d->committed.offsets.at(ii);
- bytecode << skip;
- }
- bytecode << d->committed.bytecode;
-
- QByteArray data = d->committed.data;
- while (data.count() % 4) data.append('\0');
- prog.signalTableOffset = data.count();
- data += d->buildSignalTable();
- while (data.count() % 4) data.append('\0');
- prog.exceptionDataOffset = data.count();
- data += d->buildExceptionData();
-
- prog.dataLength = 4 * ((data.size() + 3) / 4);
- prog.subscriptions = d->committed.subscriptionIds.count();
- prog.identifiers = d->committed.registeredStrings.count();
- prog.instructionCount = bytecode.count();
- prog.compiled = false;
- int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
- size += prog.dataLength;
-
- programData.resize(size);
- memcpy(programData.data(), &prog, sizeof(Program));
- if (prog.dataLength)
- memcpy((char *)((Program *)programData.data())->data(), data.constData(),
- data.size());
- memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
- bytecode.count() * sizeof(Instr));
- }
-
- return programData;
-}
-
-
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
index 03deea1e36..3d1e9255ad 100644
--- a/src/declarative/qml/qdeclarativecompileddata.cpp
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -181,6 +181,9 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
for (int ii = 0; ii < contextCaches.count(); ++ii)
contextCaches.at(ii)->release();
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+
if (importCache)
importCache->release();
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index f57f842004..d325ac48dd 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -63,7 +63,7 @@
#include "private/qdeclarativeglobal_p.h"
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4compiler_p.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QColor>
@@ -79,7 +79,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
using namespace QDeclarativeParser;
@@ -201,6 +200,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
case QVariant::String:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
break;
+ case QVariant::ByteArray:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
+ break;
case QVariant::Url:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
break;
@@ -320,16 +322,20 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
QDeclarativeParser::Value *v)
{
- QString string = v->value.asString();
-
QDeclarativeInstruction instr;
instr.line = v->location.start.line;
if (prop.isEnumType()) {
int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(string.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(string.toUtf8().constData());
+ if (v->value.isNumber()) {
+ // Preresolved enum
+ value = (int)v->value.asNumber();
+ } else {
+ // Must be a string
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
+ } else
+ value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
+ }
instr.type = QDeclarativeInstruction::StoreInteger;
instr.storeInteger.propertyIndex = prop.propertyIndex();
@@ -338,6 +344,8 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
return;
}
+ QString string = v->value.asString();
+
int type = prop.userType();
switch(type) {
case -1:
@@ -371,6 +379,13 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
instr.storeString.value = output->indexForString(string);
}
break;
+ case QVariant::ByteArray:
+ {
+ instr.type = QDeclarativeInstruction::StoreByteArray;
+ instr.storeByteArray.propertyIndex = prop.propertyIndex();
+ instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
+ }
+ break;
case QVariant::Url:
{
instr.type = QDeclarativeInstruction::StoreUrl;
@@ -642,6 +657,31 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
compileState.root = tree;
componentStat.lineNumber = tree->location.start.line;
+ // Build global import scripts
+ QStringList importedScriptIndexes;
+
+ foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ importedScriptIndexes.append(script.qualifier);
+
+ QDeclarativeInstruction import;
+ import.type = QDeclarativeInstruction::StoreImportedScript;
+ import.line = 0;
+ import.storeScript.value = output->scripts.count();
+
+ QDeclarativeScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ output->scripts << scriptData;
+ output->bytecode << import;
+ }
+
+ // We generate the importCache before we build the tree so that
+ // it can be used in the binding compiler. Given we "expect" the
+ // QML compilation to succeed, this isn't a waste.
+ output->importCache = new QDeclarativeTypeNameCache(engine);
+ for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
+ output->importCache->add(importedScriptIndexes.at(ii), ii);
+ unit->imports().populateCache(output->importCache, engine);
+
if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
return;
@@ -657,38 +697,6 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
output->bytecode << init;
- // Build global import scripts
- QHash<QString, Object::ScriptBlock> importedScripts;
- QStringList importedScriptIndexes;
-
- foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
- QString scriptCode = script.script->scriptSource();
- Object::ScriptBlock::Pragmas pragmas = script.script->pragmas();
-
- Q_ASSERT(!importedScripts.contains(script.qualifier));
-
- if (!scriptCode.isEmpty()) {
- Object::ScriptBlock &scriptBlock = importedScripts[script.qualifier];
-
- scriptBlock.code = scriptCode;
- scriptBlock.file = script.script->finalUrl().toString();
- scriptBlock.pragmas = pragmas;
- }
- }
-
- for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin();
- iter != importedScripts.end(); ++iter) {
-
- importedScriptIndexes.append(iter.key());
-
- QDeclarativeInstruction import;
- import.type = QDeclarativeInstruction::StoreImportedScript;
- import.line = 0;
- import.storeScript.value = output->scripts.count();
- output->scripts << *iter;
- output->bytecode << import;
- }
-
genObject(tree);
QDeclarativeInstruction def;
@@ -696,13 +704,6 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
def.type = QDeclarativeInstruction::SetDefault;
output->bytecode << def;
- output->importCache = new QDeclarativeTypeNameCache(engine);
-
- for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
- output->importCache->add(importedScriptIndexes.at(ii), ii);
-
- unit->imports().populateCache(output->importCache, engine);
-
Q_ASSERT(tree->metatype);
if (tree->metadata.isEmpty()) {
@@ -1283,6 +1284,7 @@ bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *ob
compileState = ComponentCompileState();
compileState.root = obj;
+ compileState.nested = true;
componentStat = ComponentStat();
componentStat.lineNumber = obj->location.start.line;
@@ -1442,8 +1444,6 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
if (typeNamespace) {
- // ### We might need to indicate that this property is a namespace
- // for the DOM API
COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
ctxt));
return true;
@@ -2227,20 +2227,35 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop
objTypeName = objType->qmlTypeName();
}
- if (!type || objTypeName != type->qmlTypeName())
+ if (!type)
return true;
QString enumValue = parts.at(1);
- int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ int value = -1;
+
+ if (objTypeName == type->qmlTypeName()) {
+ // When these two match, we can short cut the search
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
+ } else {
+ value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ }
+ } else {
+ // Otherwise we have to search the whole type
+ // This matches the logic in QDeclarativeTypeNameScriptClass
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData());
+ }
+ }
+
if (value == -1)
return true;
v->type = Value::Literal;
- v->value = QDeclarativeParser::Variant(enumValue);
+ v->value = QDeclarativeParser::Variant((double)value);
*isAssignment = true;
return true;
@@ -2412,7 +2427,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
newClassName.append("_QML_");
int idx = classIndexCounter()->fetchAndAddRelaxed(1);
newClassName.append(QByteArray::number(idx));
- if (compileState.root == obj) {
+ if (compileState.root == obj && !compileState.nested) {
QString path = output->url.path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash > -1) {
@@ -2888,25 +2903,26 @@ bool QDeclarativeCompiler::completeComponentBuild()
COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
}
- QDeclarativeBindingCompiler::Expression expr;
+ QDeclarativeV4Compiler::Expression expr;
expr.component = compileState.root;
expr.ids = compileState.ids;
+ expr.importCache = output->importCache;
+ expr.imports = unit->imports();
- QDeclarativeBindingCompiler bindingCompiler;
+ QDeclarativeV4Compiler bindingCompiler;
for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
iter != compileState.bindings.end(); ++iter) {
BindingReference &binding = *iter;
- expr.context = binding.bindingContext.object;
- expr.property = binding.property;
- expr.expression = binding.expression;
- expr.imports = unit->imports();
-
// ### We don't currently optimize for bindings on alias's - because
// of the solution to QTBUG-13719
if (!binding.property->isAlias) {
+ expr.context = binding.bindingContext.object;
+ expr.property = binding.property;
+ expr.expression = binding.expression;
+
int index = bindingCompiler.compile(expr, enginePrivate);
if (index != -1) {
binding.dataType = BindingReference::Experimental;
@@ -2947,11 +2963,8 @@ bool QDeclarativeCompiler::completeComponentBuild()
componentStat.scriptBindings.append(iter.key()->location);
}
- if (bindingCompiler.isValid()) {
+ if (bindingCompiler.isValid())
compileState.compiledBindingData = bindingCompiler.program();
- if (bindingsDump())
- QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
- }
saveComponentState();
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index 93b6a0961e..49bab759be 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -122,7 +122,7 @@ public:
QList<QScriptValue *> cachedClosures;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
- QList<QDeclarativeParser::Object::ScriptBlock> scripts;
+ QList<QDeclarativeScriptData *> scripts;
QList<QUrl> urls;
void dumpInstructions();
@@ -305,11 +305,12 @@ private:
struct ComponentCompileState
{
ComponentCompileState()
- : parserStatusCount(0), pushedProperties(0), root(0) {}
+ : parserStatusCount(0), pushedProperties(0), nested(false), root(0) {}
QHash<QString, QDeclarativeParser::Object *> ids;
QHash<int, QDeclarativeParser::Object *> idIndexes;
int parserStatusCount;
int pushedProperties;
+ bool nested;
QByteArray compiledBindingData;
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index 8238252db2..aa1bbd156f 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -836,6 +836,34 @@ QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, cons
return begin(context, creationContext, cc, start, count, &state, 0, bindings);
}
+/*
+ Try to do what's necessary for a reasonable display of the type
+ name, but no more (just enough for the client to do more extensive cleanup).
+
+ Should only be called when debugging is enabled.
+*/
+static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
+{
+ static const QString qmlMarker(QLatin1String("_QML"));
+ static const QChar underscore(QLatin1Char('_'));
+ static const QChar asterisk(QLatin1Char('*'));
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
+ QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
+ if (!type) {
+ //### optimize further?
+ int marker = typeName.indexOf(qmlMarker);
+ if (marker != -1 && marker < typeName.count() - 1) {
+ if (typeName[marker + 1] == underscore) {
+ const QString className = typeName.left(marker) + asterisk;
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
+ if (type)
+ typeName = QLatin1String(type->qmlTypeName());
+ }
+ }
+ }
+ return typeName;
+}
+
QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
QDeclarativeContextData *componentCreationContext,
QDeclarativeCompiledData *component, int start, int count,
@@ -848,10 +876,8 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
- if (isRoot) {
+ if (isRoot)
QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
- QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url);
- }
QDeclarativeContextData *ctxt = new QDeclarativeContextData;
ctxt->isInternal = true;
@@ -868,7 +894,9 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
enginePriv->inBeginCreate = true;
QDeclarativeVME vme;
+ enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
QObject *rv = vme.run(ctxt, component, start, count, bindings);
+ enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
if (vme.isError()) {
if(errors) *errors = vme.errors();
@@ -897,6 +925,11 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
if (!parentContext->isInternal)
parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
+ if (isRoot) {
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
+ QDeclarativeData *data = QDeclarativeData::get(rv);
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
+ }
}
return rv;
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index 9a60a8b4f7..f46ffdf2cf 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -117,7 +117,6 @@ private:
Q_DISABLE_COPY(QDeclarativeComponent)
friend class QDeclarativeVME;
- friend class QDeclarativeCompositeTypeData;
friend class QDeclarativeTypeData;
};
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index 7637b72eb3..4f0d704d95 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -46,9 +46,9 @@
#include "private/qdeclarativeexpression_p.h"
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
-#include "private/qdeclarativecompiledbindings_p.h"
#include "qdeclarativeinfo.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include <qscriptengine.h>
#include <QtCore/qvarlengtharray.h>
@@ -498,7 +498,7 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), publicContext(0), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -506,7 +506,7 @@ QDeclarativeContextData::QDeclarativeContextData()
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), publicContext(ctxt), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -515,8 +515,13 @@ QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
void QDeclarativeContextData::invalidate()
{
- while (childContexts)
- childContexts->invalidate();
+ while (childContexts) {
+ if (childContexts->ownedByParent) {
+ childContexts->destroy();
+ } else {
+ childContexts->invalidate();
+ }
+ }
while (componentAttached) {
QDeclarativeComponentAttached *a = componentAttached;
@@ -614,7 +619,7 @@ void QDeclarativeContextData::destroy()
delete this;
}
-void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
+void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
{
if (p) {
parent = p;
@@ -623,6 +628,7 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
if (nextChild) nextChild->prevChild = &nextChild;
prevChild = &p->childContexts;
p->childContexts = this;
+ ownedByParent = parentTakesOwnership;
}
}
@@ -662,72 +668,6 @@ void QDeclarativeContextData::addObject(QObject *o)
contextObjects = data;
}
-void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script)
-{
- if (!engine)
- return;
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- const QString &code = script.code;
- const QString &url = script.file;
- const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas;
-
- Q_ASSERT(!url.isEmpty());
-
- if (pragmas & QDeclarativeParser::Object::ScriptBlock::Shared) {
-
- QHash<QString, QScriptValue>::Iterator iter = enginePriv->m_sharedScriptImports.find(url);
- if (iter == enginePriv->m_sharedScriptImports.end()) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- iter = enginePriv->m_sharedScriptImports.insert(url, scope);
- }
-
- importedScripts.append(*iter);
-
- } else {
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- importedScripts.append(scope);
-
- }
-}
-
void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
{
idValues[idx] = obj;
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index b7e4c6aa7c..29ca091fc2 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -77,7 +77,7 @@ class QDeclarativeEngine;
class QDeclarativeExpression;
class QDeclarativeExpressionPrivate;
class QDeclarativeAbstractExpression;
-class QDeclarativeCompiledBindings;
+class QDeclarativeV4Bindings;
class QDeclarativeContextData;
class QDeclarativeContextPrivate : public QObjectPrivate
@@ -124,7 +124,7 @@ public:
QDeclarativeContextData *parent;
QDeclarativeEngine *engine;
- void setParent(QDeclarativeContextData *);
+ void setParent(QDeclarativeContextData *, bool parentTakesOwnership = false);
void refreshExpressions();
void addObject(QObject *);
@@ -135,7 +135,9 @@ public:
// If internal is false publicContext owns this.
QDeclarativeContext *asQDeclarativeContext();
QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
- bool isInternal;
+ quint32 isInternal:1;
+ quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
+ quint32 dummy:30;
QDeclarativeContext *publicContext;
// Property name cache
@@ -146,7 +148,6 @@ public:
// Any script blocks that exist on this context
QList<QScriptValue> importedScripts;
- void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script);
// Context base url
QUrl url;
@@ -188,7 +189,7 @@ public:
void setIdPropertyData(QDeclarativeIntegerCache *);
// Optimized binding pointer
- QDeclarativeCompiledBindings *optimizedBindings;
+ QDeclarativeV4Bindings *optimizedBindings;
// Linked contexts. this owns linkedContext.
QDeclarativeContextData *linkedContext;
diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp
index b5ad33d63e..97f7f4dda8 100644
--- a/src/declarative/qml/qdeclarativedirparser.cpp
+++ b/src/declarative/qml/qdeclarativedirparser.cpp
@@ -142,7 +142,7 @@ bool QDeclarativeDirParser::parse()
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2) {
reportError(lineNumber, -1,
- QString::fromUtf8("plugin directive requires 2 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
@@ -154,12 +154,22 @@ bool QDeclarativeDirParser::parse()
} else if (sections[0] == QLatin1String("internal")) {
if (sectionCount != 3) {
reportError(lineNumber, -1,
- QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
_components.append(entry);
+ } else if (sections[0] == QLatin1String("typeinfo")) {
+ if (sectionCount != 2) {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+#ifdef QT_CREATOR
+ TypeInfo typeInfo(sections[1]);
+ _typeInfos.append(typeInfo);
+#endif
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
@@ -189,7 +199,7 @@ bool QDeclarativeDirParser::parse()
}
} else {
reportError(lineNumber, -1,
- QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
}
}
@@ -229,4 +239,11 @@ QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() cons
return _components;
}
+#ifdef QT_CREATOR
+QList<TypeInfo> QDeclarativeDirParser::typeInfos() const
+{
+ return _typeInfos;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h
index 95f14bc487..d09b90e7a2 100644
--- a/src/declarative/qml/qdeclarativedirparser_p.h
+++ b/src/declarative/qml/qdeclarativedirparser_p.h
@@ -109,6 +109,19 @@ public:
QList<Component> components() const;
QList<Plugin> plugins() const;
+#ifdef QT_CREATOR
+ struct TypeInfo
+ {
+ TypeInfo() {}
+ TypeInfo(const QString &fileName)
+ : fileName(fileName) {}
+
+ QString fileName;
+ };
+
+ QList<TypeInfo> typeInfos() const;
+#endif
+
private:
void reportError(int line, int column, const QString &message);
@@ -118,6 +131,9 @@ private:
QString _source;
QList<Component> _components;
QList<Plugin> _plugins;
+#ifdef QT_CREATOR
+ QList<TypeInfo> _typeInfos;
+#endif
unsigned _isParsed: 1;
};
diff --git a/src/declarative/qml/qdeclarativedom.cpp b/src/declarative/qml/qdeclarativedom.cpp
deleted file mode 100644
index f1296aaf18..0000000000
--- a/src/declarative/qml/qdeclarativedom.cpp
+++ /dev/null
@@ -1,1835 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativedom_p.h"
-#include "private/qdeclarativedom_p_p.h"
-
-#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativescriptparser_p.h"
-#include "private/qdeclarativeglobal_p.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeDomDocumentPrivate::QDeclarativeDomDocumentPrivate()
-: root(0)
-{
-}
-
-QDeclarativeDomDocumentPrivate::~QDeclarativeDomDocumentPrivate()
-{
- if (root) root->release();
-}
-
-/*!
- \class QDeclarativeDomDocument
- \internal
- \brief The QDeclarativeDomDocument class represents the root of a QML document
-
- A QML document is a self-contained snippet of QML, usually contained in a
- single file. Each document has a root object, accessible through
- QDeclarativeDomDocument::rootObject().
-
- The QDeclarativeDomDocument class allows the programmer to inspect a QML document by
- calling QDeclarativeDomDocument::load().
-
- The following example loads a QML file from disk, and prints out its root
- object type and the properties assigned in the root object.
- \code
- QFile file(inputFileName);
- file.open(QIODevice::ReadOnly);
- QByteArray xmlData = file.readAll();
-
- QDeclarativeDomDocument document;
- document.load(qmlengine, xmlData);
-
- QDeclarativeDomObject rootObject = document.rootObject();
- qDebug() << rootObject.objectType();
- foreach(QDeclarativeDomProperty property, rootObject.properties())
- qDebug() << property.propertyName();
- \endcode
-*/
-
-/*!
- Construct an empty QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument()
-: d(new QDeclarativeDomDocumentPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument(const QDeclarativeDomDocument &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDocument
-*/
-QDeclarativeDomDocument::~QDeclarativeDomDocument()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument &QDeclarativeDomDocument::operator=(const QDeclarativeDomDocument &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns all import statements in qml.
-*/
-QList<QDeclarativeDomImport> QDeclarativeDomDocument::imports() const
-{
- return d->imports;
-}
-
-/*!
- Loads a QDeclarativeDomDocument from \a data. \a data should be valid QML
- data. On success, true is returned. If the \a data is malformed, false
- is returned and QDeclarativeDomDocument::errors() contains an error description.
-
- \sa QDeclarativeDomDocument::loadError()
-*/
-bool QDeclarativeDomDocument::load(QDeclarativeEngine *engine, const QByteArray &data, const QUrl &url)
-{
- d->errors.clear();
- d->imports.clear();
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeTypeData *td = ep->typeLoader.get(data, url, QDeclarativeTypeLoader::PreserveParser);
-
- if(td->isError()) {
- d->errors = td->errors();
- td->release();
- return false;
- } else if(!td->isCompleteOrError()) {
- QDeclarativeError error;
- error.setDescription(QLatin1String("QDeclarativeDomDocument supports local types only"));
- d->errors << error;
- td->release();
- return false;
- }
-
- for (int i = 0; i < td->parser().imports().size(); ++i) {
- QDeclarativeScriptParser::Import parserImport = td->parser().imports().at(i);
- QDeclarativeDomImport domImport;
- domImport.d->type = static_cast<QDeclarativeDomImportPrivate::Type>(parserImport.type);
- domImport.d->uri = parserImport.uri;
- domImport.d->qualifier = parserImport.qualifier;
- domImport.d->version = parserImport.version;
- d->imports += domImport;
- }
-
- if (td->parser().tree()) {
- d->root = td->parser().tree();
- d->root->addref();
- }
-
- td->release();
- return true;
-}
-
-/*!
- Returns the last load errors. The load errors will be reset after a
- successful call to load().
-
- \sa load()
-*/
-QList<QDeclarativeError> QDeclarativeDomDocument::errors() const
-{
- return d->errors;
-}
-
-/*!
- Returns the document's root object, or an invalid QDeclarativeDomObject if the
- document has no root.
-
- In the sample QML below, the root object will be the QDeclarativeItem type.
- \qml
-Item {
- Text {
- text: "Hello World"
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomDocument::rootObject() const
-{
- QDeclarativeDomObject rv;
- rv.d->object = d->root;
- if (rv.d->object) rv.d->object->addref();
- return rv;
-}
-
-QDeclarativeDomPropertyPrivate::QDeclarativeDomPropertyPrivate()
-: property(0)
-{
-}
-
-QDeclarativeDomPropertyPrivate::~QDeclarativeDomPropertyPrivate()
-{
- if (property) property->release();
-}
-
-QDeclarativeDomDynamicPropertyPrivate::QDeclarativeDomDynamicPropertyPrivate():
- valid(false)
-{
-}
-
-QDeclarativeDomDynamicPropertyPrivate::~QDeclarativeDomDynamicPropertyPrivate()
-{
- if (valid && property.defaultValue) property.defaultValue->release();
-}
-
-/*!
- \class QDeclarativeDomProperty
- \internal
- \brief The QDeclarativeDomProperty class represents one property assignment in the
- QML DOM tree
-
- Properties in QML can be assigned QML \l {QDeclarativeDomValue}{values}.
-
- \sa QDeclarativeDomObject
-*/
-
-/*!
- Construct an invalid QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty()
-: d(new QDeclarativeDomPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty(const QDeclarativeDomProperty &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::~QDeclarativeDomProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty &QDeclarativeDomProperty::operator=(const QDeclarativeDomProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomProperty, false otherwise.
-*/
-bool QDeclarativeDomProperty::isValid() const
-{
- return d->property != 0;
-}
-
-
-/*!
- Return the name of this property.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- As illustrated above, a property name can be a simple string, such as "x" or
- "y", or a more complex "dot property", such as "font.bold". In both cases
- the full name is returned ("x", "y" and "font.bold") by this method.
-
- For dot properties, a split version of the name can be accessed by calling
- QDeclarativeDomProperty::propertyNameParts().
-
- \sa QDeclarativeDomProperty::propertyNameParts()
-*/
-QByteArray QDeclarativeDomProperty::propertyName() const
-{
- return d->propertyName;
-}
-
-/*!
- Return the name of this property, split into multiple parts in the case
- of dot properties.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- For each of the properties shown above, this method would return ("x"),
- ("y") and ("font", "bold").
-
- \sa QDeclarativeDomProperty::propertyName()
-*/
-QList<QByteArray> QDeclarativeDomProperty::propertyNameParts() const
-{
- if (d->propertyName.isEmpty()) return QList<QByteArray>();
- else return d->propertyName.split('.');
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomProperty::isDefaultProperty() const
-{
- return d->property && d->property->isDefault;
-}
-
-/*!
- Returns the QDeclarativeDomValue that is assigned to this property, or an invalid
- QDeclarativeDomValue if no value is assigned.
-*/
-QDeclarativeDomValue QDeclarativeDomProperty::value() const
-{
- QDeclarativeDomValue rv;
- if (d->property) {
- rv.d->property = d->property;
- if (d->property->values.count())
- rv.d->value = d->property->values.at(0);
- else
- rv.d->value = d->property->onValues.at(0);
- rv.d->property->addref();
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomProperty::position() const
-{
- if (d && d->property) {
- return d->property->location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomProperty::length() const
-{
- if (d && d->property)
- return d->property->location.range.length;
- else
- return -1;
-}
-
-/*!
- Construct an invalid QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty():
- d(new QDeclarativeDomDynamicPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &other):
- d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::~QDeclarativeDomDynamicProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty &QDeclarativeDomDynamicProperty::operator=(const QDeclarativeDomDynamicProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-bool QDeclarativeDomDynamicProperty::isValid() const
-{
- return d && d->valid;
-}
-
-/*!
- Return the name of this dynamic property.
-
- \qml
-Item {
- property int count: 10;
-}
- \endqml
-
- As illustrated above, a dynamic property name can have a name and a
- default value ("10").
-*/
-QByteArray QDeclarativeDomDynamicProperty::propertyName() const
-{
- if (isValid())
- return d->property.name;
- else
- return QByteArray();
-}
-
-/*!
- Returns the type of the dynamic property. Note that when the property is an
- alias property, this will return -1. Use QDeclarativeDomProperty::isAlias() to check
- if the property is an alias.
-*/
-int QDeclarativeDomDynamicProperty::propertyType() const
-{
- if (isValid()) {
- switch (d->property.type) {
- case QDeclarativeParser::Object::DynamicProperty::Bool:
- return QMetaType::type("bool");
-
- case QDeclarativeParser::Object::DynamicProperty::Color:
- return QMetaType::type("QColor");
-
- case QDeclarativeParser::Object::DynamicProperty::Time:
- return QMetaType::type("QTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Date:
- return QMetaType::type("QDate");
-
- case QDeclarativeParser::Object::DynamicProperty::DateTime:
- return QMetaType::type("QDateTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Int:
- return QMetaType::type("int");
-
- case QDeclarativeParser::Object::DynamicProperty::Real:
- return sizeof(qreal) == sizeof(double) ? QMetaType::type("double") : QMetaType::type("float");
-
- case QDeclarativeParser::Object::DynamicProperty::String:
- return QMetaType::type("QString");
-
- case QDeclarativeParser::Object::DynamicProperty::Url:
- return QMetaType::type("QUrl");
-
- case QDeclarativeParser::Object::DynamicProperty::Variant:
- return QMetaType::type("QVariant");
-
- default:
- break;
- }
- }
-
- return -1;
-}
-
-QByteArray QDeclarativeDomDynamicProperty::propertyTypeName() const
-{
- if (isValid())
- return d->property.customType;
-
- return QByteArray();
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomDynamicProperty::isDefaultProperty() const
-{
- if (isValid())
- return d->property.isDefaultProperty;
- else
- return false;
-}
-
-/*!
- Returns the default value as a QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty QDeclarativeDomDynamicProperty::defaultValue() const
-{
- QDeclarativeDomProperty rp;
-
- if (isValid() && d->property.defaultValue) {
- rp.d->property = d->property.defaultValue;
- rp.d->propertyName = propertyName();
- rp.d->property->addref();
- }
-
- return rp;
-}
-
-/*!
- Returns true if this dynamic property is an alias for another property,
- false otherwise.
-*/
-bool QDeclarativeDomDynamicProperty::isAlias() const
-{
- if (isValid())
- return d->property.type == QDeclarativeParser::Object::DynamicProperty::Alias;
- else
- return false;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or 0 if
- the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::position() const
-{
- if (isValid()) {
- return d->property.location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::length() const
-{
- if (isValid())
- return d->property.location.range.length;
- else
- return -1;
-}
-
-QDeclarativeDomObjectPrivate::QDeclarativeDomObjectPrivate()
-: object(0)
-{
-}
-
-QDeclarativeDomObjectPrivate::~QDeclarativeDomObjectPrivate()
-{
- if (object) object->release();
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties() const
-{
- Properties rv;
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- object->properties.begin();
- iter != object->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
- return rv;
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties(QDeclarativeParser::Property *property) const
-{
- Properties rv;
-
- if (property->value) {
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- property->value->properties.begin();
- iter != property->value->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
-
- QByteArray name(property->name + '.');
- for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter)
- iter->second.prepend(name);
-
- } else {
- rv << qMakePair(property, property->name);
- }
-
- return rv;
-}
-
-/*!
- \class QDeclarativeDomObject
- \internal
- \brief The QDeclarativeDomObject class represents an object instantiation.
-
- Each object instantiated in a QML file has a corresponding QDeclarativeDomObject
- node in the QML DOM.
-
- In addition to the type information that determines the object to
- instantiate, QDeclarativeDomObject's also have a set of associated QDeclarativeDomProperty's.
- Each QDeclarativeDomProperty represents a QML property assignment on the instantiated
- object. For example,
-
- \qml
-QGraphicsWidget {
- opacity: 0.5
- size: "100x100"
-}
- \endqml
-
- describes a single QDeclarativeDomObject - "QGraphicsWidget" - with two properties,
- "opacity" and "size". Obviously QGraphicsWidget has many more properties than just
- these two, but the QML DOM representation only contains those assigned
- values (or bindings) in the QML file.
-*/
-
-/*!
- Construct an invalid QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject()
-: d(new QDeclarativeDomObjectPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject(const QDeclarativeDomObject &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::~QDeclarativeDomObject()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomObject.
-*/
-QDeclarativeDomObject &QDeclarativeDomObject::operator=(const QDeclarativeDomObject &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomObject, false otherwise.
-*/
-bool QDeclarativeDomObject::isValid() const
-{
- return d->object != 0;
-}
-
-/*!
- Returns the fully-qualified type name of this object.
-
- For example, the type of this object would be "Qt/4.6/Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectType() const
-{
- if (d->object) return d->object->typeName;
- else return QByteArray();
-}
-
-/*!
- Returns the type name as referenced in the qml file.
-
- For example, the type of this object would be "Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectClassName() const
-{
- if (d->object)
- return d->object->className;
- else
- return QByteArray();
-}
-
-int QDeclarativeDomObject::objectTypeMajorVersion() const
-{
- if (d->object)
- return d->object->majorVersion;
- else
- return -1;
-}
-
-int QDeclarativeDomObject::objectTypeMinorVersion() const
-{
- if (d->object)
- return d->object->minorVersion;
- else
- return -1;
-}
-
-/*!
- Returns the QML id assigned to this object, or an empty QByteArray if no id
- has been assigned.
-
- For example, the object id of this object would be "MyText".
- \qml
-Text { id: myText }
- \endqml
-*/
-QString QDeclarativeDomObject::objectId() const
-{
- if (d->object) {
- return d->object->id;
- } else {
- return QString();
- }
-}
-
-/*!
- Returns the list of assigned properties on this object.
-
- In the following example, "text" and "x" properties would be returned.
- \qml
-Text {
- text: "Hello world!"
- x: 100
-}
- \endqml
-*/
-QList<QDeclarativeDomProperty> QDeclarativeDomObject::properties() const
-{
- QList<QDeclarativeDomProperty> rv;
-
- if (!d->object || isComponent())
- return rv;
-
- QDeclarativeDomObjectPrivate::Properties properties = d->properties();
- for (int ii = 0; ii < properties.count(); ++ii) {
-
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = properties.at(ii).first;
- domProperty.d->property->addref();
- domProperty.d->propertyName = properties.at(ii).second;
- rv << domProperty;
-
- }
-
- if (d->object->defaultProperty) {
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = d->object->defaultProperty;
- domProperty.d->property->addref();
- domProperty.d->propertyName = d->object->defaultProperty->name;
- rv << domProperty;
- }
-
- return rv;
-}
-
-/*!
- Returns the object's \a name property if a value has been assigned to
- it, or an invalid QDeclarativeDomProperty otherwise.
-
- In the example below, \c {object.property("source")} would return a valid
- QDeclarativeDomProperty, and \c {object.property("tile")} an invalid QDeclarativeDomProperty.
-
- \qml
-Image { source: "sample.jpg" }
- \endqml
-*/
-QDeclarativeDomProperty QDeclarativeDomObject::property(const QByteArray &name) const
-{
- QList<QDeclarativeDomProperty> props = properties();
- for (int ii = 0; ii < props.count(); ++ii)
- if (props.at(ii).propertyName() == name)
- return props.at(ii);
- return QDeclarativeDomProperty();
-}
-
-QList<QDeclarativeDomDynamicProperty> QDeclarativeDomObject::dynamicProperties() const
-{
- QList<QDeclarativeDomDynamicProperty> properties;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- QDeclarativeDomDynamicProperty p;
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- p.d->valid = true;
-
- if (p.d->property.defaultValue)
- p.d->property.defaultValue->addref();
-
- properties.append(p);
- }
-
- return properties;
-}
-
-QDeclarativeDomDynamicProperty QDeclarativeDomObject::dynamicProperty(const QByteArray &name) const
-{
- QDeclarativeDomDynamicProperty p;
-
- if (!isValid())
- return p;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- if (d->object->dynamicProperties.at(i).name == name) {
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- if (p.d->property.defaultValue) p.d->property.defaultValue->addref();
- p.d->valid = true;
- }
- }
-
- return p;
-}
-
-/*!
- Returns true if this object is a custom type. Custom types are special
- types that allow embeddeding non-QML data, such as SVG or HTML data,
- directly into QML files.
-
- \note Currently this method will always return false, and is a placekeeper
- for future functionality.
-
- \sa QDeclarativeDomObject::customTypeData()
-*/
-bool QDeclarativeDomObject::isCustomType() const
-{
- return false;
-}
-
-/*!
- If this object represents a custom type, returns the data associated with
- the custom type, otherwise returns an empty QByteArray().
- QDeclarativeDomObject::isCustomType() can be used to check if this object represents
- a custom type.
-*/
-QByteArray QDeclarativeDomObject::customTypeData() const
-{
- return QByteArray();
-}
-
-/*!
- Returns true if this object is a sub-component object. Sub-component
- objects can be converted into QDeclarativeDomComponent instances by calling
- QDeclarativeDomObject::toComponent().
-
- \sa QDeclarativeDomObject::toComponent()
-*/
-bool QDeclarativeDomObject::isComponent() const
-{
- return (d->object && (d->object->typeName == "Qt/Component" || d->object->typeName == "QtQuick/Component"));
-}
-
-/*!
- Returns a QDeclarativeDomComponent for this object if it is a sub-component, or
- an invalid QDeclarativeDomComponent if not. QDeclarativeDomObject::isComponent() can be used
- to check if this object represents a sub-component.
-
- \sa QDeclarativeDomObject::isComponent()
-*/
-QDeclarativeDomComponent QDeclarativeDomObject::toComponent() const
-{
- QDeclarativeDomComponent rv;
- if (isComponent())
- rv.d = d;
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property assignment started
-, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::position() const
-{
- if (d && d->object)
- return d->object->location.range.offset;
- else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property assignment star
-ted upto the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::length() const
-{
- if (d && d->object)
- return d->object->location.range.length;
- else
- return -1;
-}
-
-// Returns the URL of the type, if it is an external type, or an empty URL if
-// not
-QUrl QDeclarativeDomObject::url() const
-{
- if (d && d->object)
- return d->object->url;
- else
- return QUrl();
-}
-
-QDeclarativeDomBasicValuePrivate::QDeclarativeDomBasicValuePrivate()
-: value(0)
-{
-}
-
-QDeclarativeDomBasicValuePrivate::~QDeclarativeDomBasicValuePrivate()
-{
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValueLiteral
- \internal
- \brief The QDeclarativeDomValueLiteral class represents a literal value.
-
- A literal value is a simple value, written inline with the QML. In the
- example below, the "x", "y" and "color" properties are being assigned
- literal values.
-
- \qml
-Rectangle {
- x: 10
- y: 10
- color: "red"
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::~QDeclarativeDomValueLiteral()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral &QDeclarativeDomValueLiteral::operator=(const QDeclarativeDomValueLiteral &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the literal value.
-
- In the example below, the literal value will be the string "10".
- \qml
-Rectangle { x: 10 }
- \endqml
-*/
-QString QDeclarativeDomValueLiteral::literal() const
-{
- if (d->value) return d->value->primitive();
- else return QString();
-}
-
-/*!
- \class QDeclarativeDomValueBinding
- \internal
- \brief The QDeclarativeDomValueBinding class represents a property binding.
-
- A property binding is an ECMAScript expression assigned to a property. In
- the example below, the "x" property is being assigned a property binding.
-
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::~QDeclarativeDomValueBinding()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding &QDeclarativeDomValueBinding::operator=(const QDeclarativeDomValueBinding &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the binding expression.
-
- In the example below, the string "Other.x" will be returned.
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-QString QDeclarativeDomValueBinding::binding() const
-{
- if (d->value)
- return d->value->value.asScript();
- else
- return QString();
-}
-
-/*!
- \class QDeclarativeDomValueValueSource
- \internal
- \brief The QDeclarativeDomValueValueSource class represents a value source assignment value.
-
- In QML, value sources are special value generating types that may be
- assigned to properties. Value sources inherit the QDeclarativePropertyValueSource
- class. In the example below, the "x" property is being assigned the
- NumberAnimation value source.
-
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::~QDeclarativeDomValueValueSource()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource &QDeclarativeDomValueValueSource::operator=(const QDeclarativeDomValueValueSource &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value source object.
-
- In the example below, an object representing the NumberAnimation will be
- returned.
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueSource::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- \class QDeclarativeDomValueValueInterceptor
- \internal
- \brief The QDeclarativeDomValueValueInterceptor class represents a value interceptor assignment value.
-
- In QML, value interceptor are special write-intercepting types that may be
- assigned to properties. Value interceptor inherit the QDeclarativePropertyValueInterceptor
- class. In the example below, the "x" property is being assigned the
- Behavior value interceptor.
-
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::~QDeclarativeDomValueValueInterceptor()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor &QDeclarativeDomValueValueInterceptor::operator=(const QDeclarativeDomValueValueInterceptor &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value interceptor object.
-
- In the example below, an object representing the Behavior will be
- returned.
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueInterceptor::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-QDeclarativeDomValuePrivate::QDeclarativeDomValuePrivate()
-: property(0), value(0)
-{
-}
-
-QDeclarativeDomValuePrivate::~QDeclarativeDomValuePrivate()
-{
- if (property) property->release();
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValue
- \internal
- \brief The QDeclarativeDomValue class represents a generic Qml value.
-
- QDeclarativeDomValue's can be assigned to QML \l {QDeclarativeDomProperty}{properties}. In
- QML, properties can be assigned various different values, including basic
- literals, property bindings, property value sources, objects and lists of
- values. The QDeclarativeDomValue class allows a programmer to determine the specific
- value type being assigned and access more detailed information through a
- corresponding value type class.
-
- For example, in the following example,
-
- \qml
-Text {
- text: "Hello World!"
- y: Other.y
-}
- \endqml
-
- The text property is being assigned a literal, and the y property a property
- binding. To output the values assigned to the text and y properties in the
- above example from C++,
-
- \code
- QDeclarativeDomDocument document;
- QDeclarativeDomObject root = document.rootObject();
-
- QDeclarativeDomProperty text = root.property("text");
- if (text.value().isLiteral()) {
- QDeclarativeDomValueLiteral literal = text.value().toLiteral();
- qDebug() << literal.literal();
- }
-
- QDeclarativeDomProperty y = root.property("y");
- if (y.value().isBinding()) {
- QDeclarativeDomValueBinding binding = y.value().toBinding();
- qDebug() << binding.binding();
- }
- \endcode
-*/
-
-/*!
- Construct an invalid QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue()
-: d(new QDeclarativeDomValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue(const QDeclarativeDomValue &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValue
-*/
-QDeclarativeDomValue::~QDeclarativeDomValue()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue &QDeclarativeDomValue::operator=(const QDeclarativeDomValue &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- \enum QDeclarativeDomValue::Type
-
- The type of the QDeclarativeDomValue node.
-
- \value Invalid The QDeclarativeDomValue is invalid.
- \value Literal The QDeclarativeDomValue is a literal value assignment. Use QDeclarativeDomValue::toLiteral() to access the type instance.
- \value PropertyBinding The QDeclarativeDomValue is a property binding. Use QDeclarativeDomValue::toBinding() to access the type instance.
- \value ValueSource The QDeclarativeDomValue is a property value source. Use QDeclarativeDomValue::toValueSource() to access the type instance.
- \value ValueInterceptor The QDeclarativeDomValue is a property value interceptor. Use QDeclarativeDomValue::toValueInterceptor() to access the type instance.
- \value Object The QDeclarativeDomValue is an object assignment. Use QDeclarativeDomValue::toObject() to access the type instnace.
- \value List The QDeclarativeDomValue is a list of other values. Use QDeclarativeDomValue::toList() to access the type instance.
-*/
-
-/*!
- Returns the type of this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::Type QDeclarativeDomValue::type() const
-{
- if (d->property)
- if (QDeclarativeMetaType::isList(d->property->type) ||
- (d->property && (d->property->values.count() + d->property->onValues.count()) > 1))
- return List;
-
- QDeclarativeParser::Value *value = d->value;
- if (!value && !d->property)
- return Invalid;
-
- switch(value->type) {
- case QDeclarativeParser::Value::Unknown:
- return Invalid;
- case QDeclarativeParser::Value::Literal:
- return Literal;
- case QDeclarativeParser::Value::PropertyBinding:
- return PropertyBinding;
- case QDeclarativeParser::Value::ValueSource:
- return ValueSource;
- case QDeclarativeParser::Value::ValueInterceptor:
- return ValueInterceptor;
- case QDeclarativeParser::Value::CreatedObject:
- return Object;
- case QDeclarativeParser::Value::SignalObject:
- return Invalid;
- case QDeclarativeParser::Value::SignalExpression:
- return Literal;
- case QDeclarativeParser::Value::Id:
- return Literal;
- }
- return Invalid;
-}
-
-/*!
- Returns true if this is an invalid value, otherwise false.
-*/
-bool QDeclarativeDomValue::isInvalid() const
-{
- return type() == Invalid;
-}
-
-/*!
- Returns true if this is a literal value, otherwise false.
-*/
-bool QDeclarativeDomValue::isLiteral() const
-{
- return type() == Literal;
-}
-
-/*!
- Returns true if this is a property binding value, otherwise false.
-*/
-bool QDeclarativeDomValue::isBinding() const
-{
- return type() == PropertyBinding;
-}
-
-/*!
- Returns true if this is a value source value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueSource() const
-{
- return type() == ValueSource;
-}
-
-/*!
- Returns true if this is a value interceptor value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueInterceptor() const
-{
- return type() == ValueInterceptor;
-}
-
-/*!
- Returns true if this is an object value, otherwise false.
-*/
-bool QDeclarativeDomValue::isObject() const
-{
- return type() == Object;
-}
-
-/*!
- Returns true if this is a list value, otherwise false.
-*/
-bool QDeclarativeDomValue::isList() const
-{
- return type() == List;
-}
-
-/*!
- Returns a QDeclarativeDomValueLiteral if this value is a literal type, otherwise
- returns an invalid QDeclarativeDomValueLiteral.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueLiteral QDeclarativeDomValue::toLiteral() const
-{
- QDeclarativeDomValueLiteral rv;
- if (type() == Literal) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueBinding if this value is a property binding type,
- otherwise returns an invalid QDeclarativeDomValueBinding.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueBinding QDeclarativeDomValue::toBinding() const
-{
- QDeclarativeDomValueBinding rv;
- if (type() == PropertyBinding) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueSource if this value is a property value source
- type, otherwise returns an invalid QDeclarativeDomValueValueSource.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueSource QDeclarativeDomValue::toValueSource() const
-{
- QDeclarativeDomValueValueSource rv;
- if (type() == ValueSource) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueInterceptor if this value is a property value interceptor
- type, otherwise returns an invalid QDeclarativeDomValueValueInterceptor.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueInterceptor QDeclarativeDomValue::toValueInterceptor() const
-{
- QDeclarativeDomValueValueInterceptor rv;
- if (type() == ValueInterceptor) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomObject if this value is an object assignment type, otherwise
- returns an invalid QDeclarativeDomObject.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomObject QDeclarativeDomValue::toObject() const
-{
- QDeclarativeDomObject rv;
- if (type() == Object) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomList if this value is a list type, otherwise returns an
- invalid QDeclarativeDomList.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomList QDeclarativeDomValue::toList() const
-{
- QDeclarativeDomList rv;
- if (type() == List) {
- rv.d = d;
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property value startd, or -1
- if the value is invalid.
-*/
-int QDeclarativeDomValue::position() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.offset;
-}
-
-/*!
- Returns the length in the input data from where the property value started u
-pto the end of it, or -1 if the value is invalid.
-*/
-int QDeclarativeDomValue::length() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.length;
-}
-
-/*!
- \class QDeclarativeDomList
- \internal
- \brief The QDeclarativeDomList class represents a list of values assigned to a QML property.
-
- Lists of values can be assigned to properties. For example, the following
- example assigns multiple objects to Item's "children" property
- \qml
-Item {
- children: [
- Text { },
- Rectangle { }
- ]
-}
- \endqml
-
- Lists can also be implicitly created by assigning multiple
- \l {QDeclarativeDomValueValueSource}{value sources} or constants to a property.
- \qml
-Item {
- x: 10
- x: NumberAnimation {
- running: false
- from: 0
- to: 100
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList(const QDeclarativeDomList &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomList.
-*/
-QDeclarativeDomList::~QDeclarativeDomList()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomList.
-*/
-QDeclarativeDomList &QDeclarativeDomList::operator=(const QDeclarativeDomList &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the list of QDeclarativeDomValue's.
-*/
-QList<QDeclarativeDomValue> QDeclarativeDomList::values() const
-{
- QList<QDeclarativeDomValue> rv;
- if (!d->property)
- return rv;
-
- for (int ii = 0; ii < d->property->values.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->values.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- for (int ii = 0; ii < d->property->onValues.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->onValues.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- return rv;
-}
-
-/*!
- Returns the position in the input data where the list started, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomList::position() const
-{
- if (d && d->property) {
- return d->property->listValueRange.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the list started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomList::length() const
-{
- if (d && d->property)
- return d->property->listValueRange.length;
- else
- return -1;
-}
-
-/*!
- Returns a list of positions of the commas in the QML file.
-*/
-QList<int> QDeclarativeDomList:: commaPositions() const
-{
- if (d && d->property)
- return d->property->listCommaPositions;
- else
- return QList<int>();
-}
-
-/*!
- \class QDeclarativeDomComponent
- \internal
- \brief The QDeclarativeDomComponent class represents sub-component within a QML document.
-
- Sub-components are QDeclarativeComponents defined within a QML document. The
- following example shows the definition of a sub-component with the id
- "listDelegate".
-
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-
- Like QDeclarativeDomDocument's, components contain a single root object.
-*/
-
-/*!
- Construct an empty QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent(const QDeclarativeDomComponent &other)
-: QDeclarativeDomObject(other)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::~QDeclarativeDomComponent()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent &QDeclarativeDomComponent::operator=(const QDeclarativeDomComponent &other)
-{
- static_cast<QDeclarativeDomObject &>(*this) = other;
- return *this;
-}
-
-/*!
- Returns the component's root object.
-
- In the example below, the root object is the "Text" object.
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomComponent::componentRoot() const
-{
- QDeclarativeDomObject rv;
- if (d->object) {
- QDeclarativeParser::Object *obj = 0;
- if (d->object->defaultProperty &&
- d->object->defaultProperty->values.count() == 1 &&
- d->object->defaultProperty->values.at(0)->object)
- obj = d->object->defaultProperty->values.at(0)->object;
-
- if (obj) {
- rv.d->object = obj;
- rv.d->object->addref();
- }
- }
-
- return rv;
-}
-
-QDeclarativeDomImportPrivate::QDeclarativeDomImportPrivate()
-: type(File)
-{
-}
-
-QDeclarativeDomImportPrivate::~QDeclarativeDomImportPrivate()
-{
-}
-
-/*!
- \class QDeclarativeDomImport
- \internal
- \brief The QDeclarativeDomImport class represents an import statement.
-*/
-
-/*!
- Construct an empty QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport()
-: d(new QDeclarativeDomImportPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport(const QDeclarativeDomImport &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::~QDeclarativeDomImport()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomImport.
-*/
-QDeclarativeDomImport &QDeclarativeDomImport::operator=(const QDeclarativeDomImport &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the type of the import.
- */
-QDeclarativeDomImport::Type QDeclarativeDomImport::type() const
-{
- return static_cast<QDeclarativeDomImport::Type>(d->type);
-}
-
-/*!
- Returns the URI of the import (e.g. 'subdir' or 'com.nokia.Qt')
- */
-QString QDeclarativeDomImport::uri() const
-{
- return d->uri;
-}
-
-/*!
- Returns the version specified by the import. An empty string if no version was specified.
- */
-QString QDeclarativeDomImport::version() const
-{
- return d->version;
-}
-
-/*!
- Returns the (optional) qualifier string (the token following the 'as' keyword) of the import.
- */
-QString QDeclarativeDomImport::qualifier() const
-{
- return d->qualifier;
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedom_p.h b/src/declarative/qml/qdeclarativedom_p.h
deleted file mode 100644
index 64300d47e7..0000000000
--- a/src/declarative/qml/qdeclarativedom_p.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEDOM_P_H
-#define QDECLARATIVEDOM_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qdeclarativeerror.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qshareddata.h>
-
-#include <private/qdeclarativeglobal_p.h>
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Declarative)
-
-class QString;
-class QByteArray;
-class QDeclarativeDomObject;
-class QDeclarativeDomList;
-class QDeclarativeDomValue;
-class QDeclarativeEngine;
-class QDeclarativeDomComponent;
-class QDeclarativeDomImport;
-class QIODevice;
-
-class QDeclarativeDomDocumentPrivate;
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDocument
-{
-public:
- QDeclarativeDomDocument();
- QDeclarativeDomDocument(const QDeclarativeDomDocument &);
- ~QDeclarativeDomDocument();
- QDeclarativeDomDocument &operator=(const QDeclarativeDomDocument &);
-
- QList<QDeclarativeDomImport> imports() const;
-
- QList<QDeclarativeError> errors() const;
- bool load(QDeclarativeEngine *, const QByteArray &, const QUrl & = QUrl());
-
- QDeclarativeDomObject rootObject() const;
-
-private:
- QSharedDataPointer<QDeclarativeDomDocumentPrivate> d;
-};
-
-class QDeclarativeDomPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomProperty
-{
-public:
- QDeclarativeDomProperty();
- QDeclarativeDomProperty(const QDeclarativeDomProperty &);
- ~QDeclarativeDomProperty();
- QDeclarativeDomProperty &operator=(const QDeclarativeDomProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- QList<QByteArray> propertyNameParts() const;
-
- bool isDefaultProperty() const;
-
- QDeclarativeDomValue value() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- friend class QDeclarativeDomDynamicProperty;
- QSharedDataPointer<QDeclarativeDomPropertyPrivate> d;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDynamicProperty
-{
-public:
- QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &);
- ~QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty &operator=(const QDeclarativeDomDynamicProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- int propertyType() const;
- QByteArray propertyTypeName() const;
-
- bool isDefaultProperty() const;
- QDeclarativeDomProperty defaultValue() const;
-
- bool isAlias() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- QSharedDataPointer<QDeclarativeDomDynamicPropertyPrivate> d;
-};
-
-class QDeclarativeDomObjectPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomObject
-{
-public:
- QDeclarativeDomObject();
- QDeclarativeDomObject(const QDeclarativeDomObject &);
- ~QDeclarativeDomObject();
- QDeclarativeDomObject &operator=(const QDeclarativeDomObject &);
-
- bool isValid() const;
-
- QByteArray objectType() const;
- QByteArray objectClassName() const;
-
- int objectTypeMajorVersion() const;
- int objectTypeMinorVersion() const;
-
- QString objectId() const;
-
- QList<QDeclarativeDomProperty> properties() const;
- QDeclarativeDomProperty property(const QByteArray &) const;
-
- QList<QDeclarativeDomDynamicProperty> dynamicProperties() const;
- QDeclarativeDomDynamicProperty dynamicProperty(const QByteArray &) const;
-
- bool isCustomType() const;
- QByteArray customTypeData() const;
-
- bool isComponent() const;
- QDeclarativeDomComponent toComponent() const;
-
- int position() const;
- int length() const;
-
- QUrl url() const;
-private:
- friend class QDeclarativeDomDocument;
- friend class QDeclarativeDomComponent;
- friend class QDeclarativeDomValue;
- friend class QDeclarativeDomValueValueSource;
- friend class QDeclarativeDomValueValueInterceptor;
- QSharedDataPointer<QDeclarativeDomObjectPrivate> d;
-};
-
-class QDeclarativeDomValuePrivate;
-class QDeclarativeDomBasicValuePrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueLiteral
-{
-public:
- QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &);
- ~QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral &operator=(const QDeclarativeDomValueLiteral &);
-
- QString literal() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueBinding
-{
-public:
- QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &);
- ~QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding &operator=(const QDeclarativeDomValueBinding &);
-
- QString binding() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueSource
-{
-public:
- QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &);
- ~QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource &operator=(const QDeclarativeDomValueValueSource &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueInterceptor
-{
-public:
- QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &);
- ~QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor &operator=(const QDeclarativeDomValueValueInterceptor &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomComponent : public QDeclarativeDomObject
-{
-public:
- QDeclarativeDomComponent();
- QDeclarativeDomComponent(const QDeclarativeDomComponent &);
- ~QDeclarativeDomComponent();
- QDeclarativeDomComponent &operator=(const QDeclarativeDomComponent &);
-
- QDeclarativeDomObject componentRoot() const;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValue
-{
-public:
- enum Type {
- Invalid,
- Literal,
- PropertyBinding,
- ValueSource,
- ValueInterceptor,
- Object,
- List
- };
-
- QDeclarativeDomValue();
- QDeclarativeDomValue(const QDeclarativeDomValue &);
- ~QDeclarativeDomValue();
- QDeclarativeDomValue &operator=(const QDeclarativeDomValue &);
-
- Type type() const;
-
- bool isInvalid() const;
- bool isLiteral() const;
- bool isBinding() const;
- bool isValueSource() const;
- bool isValueInterceptor() const;
- bool isObject() const;
- bool isList() const;
-
- QDeclarativeDomValueLiteral toLiteral() const;
- QDeclarativeDomValueBinding toBinding() const;
- QDeclarativeDomValueValueSource toValueSource() const;
- QDeclarativeDomValueValueInterceptor toValueInterceptor() const;
- QDeclarativeDomObject toObject() const;
- QDeclarativeDomList toList() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomProperty;
- friend class QDeclarativeDomList;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomList
-{
-public:
- QDeclarativeDomList();
- QDeclarativeDomList(const QDeclarativeDomList &);
- ~QDeclarativeDomList();
- QDeclarativeDomList &operator=(const QDeclarativeDomList &);
-
- QList<QDeclarativeDomValue> values() const;
-
- int position() const;
- int length() const;
-
- QList<int> commaPositions() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class QDeclarativeDomImportPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomImport
-{
-public:
- enum Type { Library, File };
-
- QDeclarativeDomImport();
- QDeclarativeDomImport(const QDeclarativeDomImport &);
- ~QDeclarativeDomImport();
- QDeclarativeDomImport &operator=(const QDeclarativeDomImport &);
-
- Type type() const;
- QString uri() const;
- QString version() const;
- QString qualifier() const;
-
-private:
- friend class QDeclarativeDomDocument;
- QSharedDataPointer<QDeclarativeDomImportPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-#endif // QDECLARATIVEDOM_P_H
diff --git a/src/declarative/qml/qdeclarativedom_p_p.h b/src/declarative/qml/qdeclarativedom_p_p.h
deleted file mode 100644
index 7ce99ec74d..0000000000
--- a/src/declarative/qml/qdeclarativedom_p_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEDOM_P_P_H
-#define QDECLARATIVEDOM_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qdeclarativeparser_p.h"
-
-#include <QtCore/QtGlobal>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeDomDocumentPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDocumentPrivate();
- QDeclarativeDomDocumentPrivate(const QDeclarativeDomDocumentPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDocumentPrivate();
-
- QList<QDeclarativeError> errors;
- QList<QDeclarativeDomImport> imports;
- QDeclarativeParser::Object *root;
- QList<int> automaticSemicolonOffsets;
-};
-
-class QDeclarativeDomObjectPrivate : public QSharedData
-{
-public:
- QDeclarativeDomObjectPrivate();
- QDeclarativeDomObjectPrivate(const QDeclarativeDomObjectPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomObjectPrivate();
-
- typedef QList<QPair<QDeclarativeParser::Property *, QByteArray> > Properties;
- Properties properties() const;
- Properties properties(QDeclarativeParser::Property *) const;
-
- QDeclarativeParser::Object *object;
-};
-
-class QDeclarativeDomPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomPropertyPrivate();
- QDeclarativeDomPropertyPrivate(const QDeclarativeDomPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomPropertyPrivate();
-
- QByteArray propertyName;
- QDeclarativeParser::Property *property;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDynamicPropertyPrivate();
- QDeclarativeDomDynamicPropertyPrivate(const QDeclarativeDomDynamicPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDynamicPropertyPrivate();
-
- bool valid;
- QDeclarativeParser::Object::DynamicProperty property;
-};
-
-class QDeclarativeDomValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomValuePrivate();
- QDeclarativeDomValuePrivate(const QDeclarativeDomValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomValuePrivate();
-
- QDeclarativeParser::Property *property;
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomBasicValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomBasicValuePrivate();
- QDeclarativeDomBasicValuePrivate(const QDeclarativeDomBasicValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomBasicValuePrivate();
-
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomImportPrivate : public QSharedData
-{
-public:
- QDeclarativeDomImportPrivate();
- QDeclarativeDomImportPrivate(const QDeclarativeDomImportPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomImportPrivate();
-
- enum Type { Library, File };
-
- Type type;
- QString uri;
- QString version;
- QString qualifier;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEDOM_P_P_H
-
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 9fde18c81c..ba0ddbbfaf 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -55,6 +55,7 @@
#include "private/qdeclarativestringconverters_p.h"
#include "private/qdeclarativexmlhttprequest_p.h"
#include "private/qdeclarativesqldatabase_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativetypenamescriptclass_p.h"
#include "private/qdeclarativelistscriptclass_p.h"
#include "qdeclarativescriptstring.h"
@@ -103,6 +104,8 @@
#include <private/qdeclarativeitemsmodule_p.h>
#include <private/qdeclarativeutilmodule_p.h>
+#include <private/qsgitemsmodule_p.h>
+#include <qsgtexture.h>
#ifdef Q_OS_WIN // for %APPDATA%
#include <qt_windows.h>
@@ -349,13 +352,15 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0),
- typeLoader(e), importDatabase(e), uniqueId(1)
+ scarceResources(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ sgContext(0)
{
if (!qt_QmlQtModule_registered) {
qt_QmlQtModule_registered = true;
QDeclarativeItemModule::defineModule();
QDeclarativeUtilModule::defineModule();
QDeclarativeEnginePrivate::defineModule();
+ QSGItemsModule::defineModule();
QDeclarativeValueTypeFactory::registerValueTypes();
}
globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
@@ -499,6 +504,8 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
contextClass = 0;
delete objectClass;
objectClass = 0;
+ delete scarceResourceClass;
+ scarceResourceClass = 0;
delete valueTypeClass;
valueTypeClass = 0;
delete typeNameClass;
@@ -514,7 +521,10 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
(*iter)->release();
for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
(*iter)->release();
-
+ for(QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
+ delete (*iter)->qobjectApi;
+ delete *iter;
+ }
}
void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs)
@@ -571,6 +581,7 @@ void QDeclarativeEnginePrivate::init()
contextClass = new QDeclarativeContextScriptClass(q);
objectClass = new QDeclarativeObjectScriptClass(q);
+ scarceResourceClass = new QDeclarativeScarceResourceScriptClass(q);
valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
typeNameClass = new QDeclarativeTypeNameScriptClass(q);
listClass = new QDeclarativeListScriptClass(q);
@@ -647,6 +658,22 @@ QDeclarativeEngine::~QDeclarativeEngine()
Q_D(QDeclarativeEngine);
if (d->isDebugging)
QDeclarativeEngineDebugServer::instance()->remEngine(this);
+
+ // if we are the parent of any of the qobject module api instances,
+ // we need to remove them from our internal list, in order to prevent
+ // a segfault in engine private dtor.
+ QList<QDeclarativeMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
+ QObject *currQObjectApi = 0;
+ QDeclarativeMetaType::ModuleApiInstance *currInstance = 0;
+ foreach (const QDeclarativeMetaType::ModuleApi &key, keys) {
+ currInstance = d->moduleApiInstances.value(key);
+ currQObjectApi = currInstance->qobjectApi;
+ if (this->children().contains(currQObjectApi)) {
+ delete currQObjectApi;
+ delete currInstance;
+ d->moduleApiInstances.remove(key);
+ }
+ }
}
/*! \fn void QDeclarativeEngine::quit()
@@ -813,6 +840,18 @@ QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProvider
return static_cast<QDeclarativeImageProvider::ImageType>(-1);
}
+QSGTexture *QDeclarativeEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ return provider->requestTexture(imageId, size, req_size);
+ }
+ return 0;
+}
+
QImage QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
{
QMutexLocker locker(&mutex);
@@ -1699,9 +1738,6 @@ QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine
qsreal w = ctxt->argument(2).toNumber();
qsreal h = ctxt->argument(3).toNumber();
- if (w < 0 || h < 0)
- return engine->nullValue();
-
return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
@@ -2056,7 +2092,9 @@ QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine
QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
{
- if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ if (variantIsScarceResource(val)) {
+ return scarceResourceClass->newScarceResource(val);
+ } else if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
QDeclarativeListReferencePrivate *p =
QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
if (p->object) {
@@ -2085,11 +2123,69 @@ QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &v
}
}
+/*
+ If the variant is a scarce resource (consumes a large amount of memory, or
+ only a limited number of them can be held in memory at any given time without
+ exhausting supply for future use) we need to release the scarce resource
+ after evaluation of the javascript binding is complete.
+ */
+bool QDeclarativeEnginePrivate::variantIsScarceResource(const QVariant& val)
+{
+ if (val.type() == QVariant::Pixmap) {
+ return true;
+ } else if (val.type() == QVariant::Image) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ This function should be called prior to evaluation of any js expression,
+ so that scarce resources are not freed prematurely (eg, if there is a
+ nested javascript expression).
+ */
+void QDeclarativeEnginePrivate::referenceScarceResources()
+{
+ scarceResourcesRefCount += 1;
+}
+
+/*
+ This function should be called after evaluation of the js expression is
+ complete, and so the scarce resources may be freed safely.
+ */
+void QDeclarativeEnginePrivate::dereferenceScarceResources()
+{
+ Q_ASSERT(scarceResourcesRefCount > 0);
+ scarceResourcesRefCount -= 1;
+
+ // if the refcount is zero, then evaluation of the "top level"
+ // expression must have completed. We can safely release the
+ // scarce resources.
+ if (scarceResourcesRefCount == 0) {
+ // iterate through the list and release them all.
+ // note that the actual SRD is owned by the JS engine,
+ // so we cannot delete the SRD; but we can free the
+ // memory used by the variant in the SRD.
+ ScarceResourceData *srd = 0;
+ while (scarceResources) {
+ srd = scarceResources; // srd points to the "old" (current) head of the list
+ scarceResources = srd->next; // srd->next is the "new" head of the list
+ if (srd->next) srd->next->prev = &scarceResources; // newHead->prev = listptr.
+ srd->next = 0;
+ srd->prev = 0;
+ srd->releaseResource(); // release the old head node.
+ }
+ }
+}
+
QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
{
QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
if (dc == objectClass)
return QVariant::fromValue(objectClass->toQObject(val));
+ else if (dc == scarceResourceClass)
+ return scarceResourceClass->toVariant(val);
else if (dc == valueTypeClass)
return valueTypeClass->toVariant(val);
else if (dc == contextClass)
@@ -2218,6 +2314,20 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
+ On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
+
+ The plugin has to be a Qt plugin which implements the QDeclarativeExtensionPlugin interface.
+*/
+bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
+{
+ Q_D(QDeclarativeEngine);
+ return d->importDatabase.importPlugin(filePath, uri, errors);
+}
+
+/*!
+ Imports the plugin named \a filePath with the \a uri provided.
+ Returns true if the plugin was successfully imported; otherwise returns false.
+
On failure and if non-null, *\a errorString will be set to a message describing the failure.
The plugin has to be a Qt plugin which implements the QDeclarativeExtensionPlugin interface.
@@ -2225,7 +2335,18 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
{
Q_D(QDeclarativeEngine);
- return d->importDatabase.importPlugin(filePath, uri, errorString);
+ QList<QDeclarativeError> errors;
+ bool retn = d->importDatabase.importPlugin(filePath, uri, &errors);
+ if (!errors.isEmpty()) {
+ QString builtError;
+ for (int i = 0; i < errors.size(); ++i) {
+ builtError = QString(QLatin1String("%1\n %2"))
+ .arg(builtError)
+ .arg(errors.at(i).toString());
+ }
+ *errorString = builtError;
+ }
+ return retn;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
index 631fc5ec57..8db3db8096 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -86,7 +86,8 @@ public:
void setPluginPathList(const QStringList &paths);
void addPluginPath(const QString& dir);
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ bool importPlugin(const QString &filePath, const QString &uri, QString *errorString); // XXX: Qt 5: Remove this function
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors);
void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *);
QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const;
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 88b4e800f8..fadedf41dd 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -67,6 +67,7 @@
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
#include "private/qdeclarativeobjectscriptclass_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativecontextscriptclass_p.h"
#include "private/qdeclarativevaluetypescriptclass_p.h"
#include "private/qdeclarativemetatype_p.h"
@@ -93,6 +94,8 @@ class QDeclarativeExpression;
class QDeclarativeContextScriptClass;
class QDeclarativeImportDatabase;
class QDeclarativeObjectScriptClass;
+class QDeclarativeScarceResourceScriptClass;
+class ScarceResourceData;
class QDeclarativeTypeNameScriptClass;
class QDeclarativeValueTypeScriptClass;
class QScriptEngineDebugger;
@@ -110,6 +113,8 @@ class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
class QDeclarativeGlobalScriptClass;
class QDir;
+class QSGTexture;
+class QSGContext;
class QDeclarativeScriptEngine : public QScriptEngine
{
@@ -169,6 +174,7 @@ public:
QDeclarativeContextData *sharedContext;
QObject *sharedScope;
QDeclarativeObjectScriptClass *objectClass;
+ QDeclarativeScarceResourceScriptClass *scarceResourceClass;
QDeclarativeValueTypeScriptClass *valueTypeClass;
QDeclarativeTypeNameScriptClass *typeNameClass;
QDeclarativeListScriptClass *listClass;
@@ -233,9 +239,22 @@ public:
QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders;
QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
+ QSGTexture *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ /*
+ A scarce resource (like a large pixmap or texture) will be cached in a
+ JavaScript wrapper object when accessed in a binding or other js expression.
+ We need some way to automatically release that scarce resource prior to normal
+ garbage collection (unless the user explicitly preserves the resource).
+ */
+ ScarceResourceData* scarceResources;
+ int scarceResourcesRefCount;
+ static bool variantIsScarceResource(const QVariant& val);
+ void referenceScarceResources();
+ void dereferenceScarceResources();
+
mutable QMutex mutex;
QDeclarativeTypeLoader typeLoader;
@@ -250,6 +269,8 @@ public:
QDeclarativeValueTypeFactory valueTypes;
+ QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
+
QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
inline QDeclarativePropertyCache *cache(QObject *obj);
@@ -270,8 +291,6 @@ public:
QHash<int, int> m_qmlLists;
QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
- QHash<QString, QScriptValue> m_sharedScriptImports;
-
QScriptValue scriptValueFromVariant(const QVariant &);
QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
@@ -327,6 +346,8 @@ public:
static void defineModule();
static bool qml_debugging_enabled;
+
+ QSGContext *sgContext;
};
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index 7a85adaa6e..afd1be1025 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -630,7 +630,6 @@ QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope,
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
@@ -663,8 +662,10 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
-
- return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+ return retn;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp
index f111c201fa..c9b399cc32 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.cpp
+++ b/src/declarative/qml/qdeclarativeimageprovider.cpp
@@ -159,6 +159,8 @@ public:
requestImage() method will be called for all image requests.
\value Pixmap The Image Provider provides QPixmap images. The
requestPixmap() method will be called for all image requests.
+ \value Texture The Image Provider provides QSGTextureProvider based images.
+ The requestTexture() method will be called for all image requests. \omitvalue
*/
/*!
@@ -243,5 +245,36 @@ QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size,
return QPixmap();
}
+
+/*!
+ Implement this method to return the texture with \a id. The default
+ implementation returns 0.
+
+ The \a id is the requested image source, with the "image:" scheme and
+ provider identifier removed. For example, if the image \l{Image::}{source}
+ was "image://myprovider/icons/home", the given \a id would be "icons/home".
+
+ The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
+ an Image element. If \a requestedSize is a valid size, the image
+ returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image. This
+ is used to set the \l {Item::}{width} and \l {Item::}{height} of the
+ relevant \l Image if these values have not been set explicitly.
+
+ \note this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QSGTexture *QDeclarativeImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Texture)
+ qWarning("ImageProvider supports Texture type but has not implemented requestTexture()");
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h
index 7f13fda85b..e5e80f227c 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.h
+++ b/src/declarative/qml/qdeclarativeimageprovider.h
@@ -52,13 +52,15 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QDeclarativeImageProviderPrivate;
+class QSGTexture;
class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider
{
public:
enum ImageType {
Image,
- Pixmap
+ Pixmap,
+ Texture
};
QDeclarativeImageProvider(ImageType type);
@@ -68,6 +70,7 @@ public:
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QSGTexture *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
private:
QDeclarativeImageProviderPrivate *d;
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp
index e8d593fd1a..c5abe2c75d 100644
--- a/src/declarative/qml/qdeclarativeimport.cpp
+++ b/src/declarative/qml/qdeclarativeimport.cpp
@@ -83,7 +83,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
QUrl *base = 0, bool *typeRecursionDetected = 0);
bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base = 0, QString *errorString = 0);
+ QUrl* url_return, QUrl *base = 0, QList<QDeclarativeError> *errors = 0);
};
class QDeclarativeImportsPrivate {
@@ -93,15 +93,15 @@ public:
bool importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database);
bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString);
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors);
bool find(const QByteArray& type, int *vmajor, int *vminor,
- QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
+ QDeclarativeType** type_return, QUrl* url_return, QList<QDeclarativeError> *errors);
QDeclarativeImportedNamespace *findNamespace(const QString& type);
@@ -163,7 +163,7 @@ QUrl QDeclarativeImports::baseUrl() const
static QDeclarativeTypeNameCache *
cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set,
- QDeclarativeTypeNameCache *cache)
+ QDeclarativeTypeNameCache *cache, bool importWasQualified)
{
if (!cache)
cache = new QDeclarativeTypeNameCache(engine);
@@ -171,10 +171,27 @@ cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespac
QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
for (int ii = 0; ii < set.uris.count(); ++ii) {
- QByteArray base = set.uris.at(ii).toUtf8() + '/';
+ QByteArray uri = set.uris.at(ii).toUtf8();
int major = set.majversions.at(ii);
int minor = set.minversions.at(ii);
+ if (importWasQualified) {
+ QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(uri, major, minor);
+ if (moduleApi.script || moduleApi.qobject) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeMetaType::ModuleApiInstance *a = ep->moduleApiInstances.value(moduleApi);
+ if (!a) {
+ a = new QDeclarativeMetaType::ModuleApiInstance;
+ a->scriptCallback = moduleApi.script;
+ a->qobjectCallback = moduleApi.qobject;
+ ep->moduleApiInstances.insert(moduleApi, a);
+ }
+ cache->setModuleApi(a);
+ }
+ }
+
+ QByteArray base = uri + '/';
+
foreach (QDeclarativeType *type, types) {
if (type->qmlTypeName().startsWith(base) &&
type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
@@ -200,15 +217,15 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
if (d) {
if (!d->typeNamespace)
- cacheForNamespace(engine, *(*iter), d->typeNamespace);
+ cacheForNamespace(engine, *(*iter), d->typeNamespace, true);
} else {
- QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
+ QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0, true);
cache->add(iter.key(), nc);
nc->release();
}
}
- cacheForNamespace(engine, set, cache);
+ cacheForNamespace(engine, set, cache, false);
}
/*!
@@ -227,7 +244,7 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
*/
bool QDeclarativeImports::resolveType(const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
- QDeclarativeImportedNamespace** ns_return, QString *errorString) const
+ QDeclarativeImportedNamespace** ns_return, QList<QDeclarativeError> *errors) const
{
QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
if (ns) {
@@ -236,7 +253,7 @@ bool QDeclarativeImports::resolveType(const QByteArray& type,
return true;
}
if (type_return || url_return) {
- if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
+ if (d->find(type,vmaj,vmin,type_return,url_return, errors)) {
if (qmlImportTrace()) {
if (type_return && *type_return && url_return && !url_return->isEmpty())
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
@@ -351,13 +368,16 @@ QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database,
- QDeclarativeDirComponents* components, QString *errorString)
+ QDeclarativeDirComponents* components, QList<QDeclarativeError> *errors)
{
QFile file(absoluteFilePath);
QString filecontent;
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
} else if (file.open(QFile::ReadOnly)) {
filecontent = QString::fromUtf8(file.readAll());
@@ -365,15 +385,29 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
<< "loaded " << absoluteFilePath;
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QDir dir = QFileInfo(file).dir();
+ QUrl url = QUrl::fromLocalFile(absoluteFilePath);
QDeclarativeDirParser qmldirParser;
qmldirParser.setSource(filecontent);
- qmldirParser.parse();
+ qmldirParser.setUrl(url);
+
+ // propagate any errors reported by the parser back up to the typeloader.
+ if (qmldirParser.parse()) {
+ if (errors) {
+ for (int i = 0; i < qmldirParser.errors().size(); ++i) {
+ errors->prepend(qmldirParser.errors().at(i));
+ }
+ }
+ return false;
+ }
if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
@@ -390,14 +424,26 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
}
#endif
if (!resolvedFilePath.isEmpty()) {
- if (!database->importPlugin(resolvedFilePath, uri, errorString)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString);
+ if (!database->importPlugin(resolvedFilePath, uri, errors)) {
+ if (errors) {
+ // XXX TODO: should we leave the import plugin error alone?
+ // Here, we pop it off the top and coalesce it into this error's message.
+ // The reason is that the lower level may add url and line/column numbering information.
+ QDeclarativeError poppedError = errors->takeFirst();
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
}
@@ -443,7 +489,7 @@ QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclara
bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString)
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors)
{
QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
QString uri = uri_arg;
@@ -477,7 +523,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -496,7 +542,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -516,7 +562,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -527,12 +573,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
versionFound = true;
if (!versionFound && qmldircomponents.isEmpty()) {
- if (errorString) {
+ if (errors) {
bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
+ QDeclarativeError error; // we don't set the url or line or column as these will be set by the loader.
if (anyversion)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
else
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
+ errors->prepend(error);
}
return false;
}
@@ -545,15 +593,19 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(dir);
if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg);
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
+ error.setUrl(importUrl);
+ errors->prepend(error);
+ }
return false; // local import dirs must exist
}
uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
if (uri.endsWith(QLatin1Char('/')))
uri.chop(1);
if (QFile::exists(localFileOrQrc)) {
- if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString))
+ if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errors))
return false;
}
} else {
@@ -562,11 +614,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(localFileOrQrc);
if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
if (localFileOrQrc.isEmpty())
- *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
else
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(importUrl);
+ errors->prepend(error);
}
return false;
}
@@ -598,7 +653,11 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin)
|| highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin))
{
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ if (errors) {
+ QDeclarativeError error; // we don't set the url or line or column information, as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+ errors->prepend(error);
+ }
return false;
}
}
@@ -613,7 +672,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
}
bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QString *errorString)
+ QUrl* url_return, QList<QDeclarativeError> *errors)
{
QDeclarativeImportedNamespace *s = 0;
int slash = type.indexOf('/');
@@ -621,14 +680,20 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
QString namespaceName = QString::fromUtf8(type.left(slash));
s = set.value(namespaceName);
if (!s) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+ errors->prepend(error);
+ }
return false;
}
int nslash = type.indexOf('/',slash+1);
if (nslash > 0) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
return false;
}
} else {
@@ -636,7 +701,7 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
}
QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
if (s) {
- if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
return true;
if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
// qualified, and only 1 url
@@ -654,7 +719,7 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
}
bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base, QString *errorString)
+ QUrl* url_return, QUrl *base, QList<QDeclarativeError> *errors)
{
bool typeRecursionDetected = false;
for (int i=0; i<urls.count(); ++i) {
@@ -663,7 +728,7 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
// check for type clashes
for (int j = i+1; j<urls.count(); ++j) {
if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
- if (errorString) {
+ if (errors) {
QString u1 = urls.at(i);
QString u2 = urls.at(j);
if (base) {
@@ -683,16 +748,16 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
}
}
- if (u1 != u2)
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2")
- .arg(u1).arg(u2);
- else
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
- .arg(u1)
- .arg(majversions.at(i)).arg(minversions.at(i))
- .arg(majversions.at(j)).arg(minversions.at(j));
+ QDeclarativeError error;
+ if (u1 != u2) {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ } else {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+ .arg(u1)
+ .arg(majversions.at(i)).arg(minversions.at(i))
+ .arg(majversions.at(j)).arg(minversions.at(j)));
+ }
+ errors->prepend(error);
}
return false;
}
@@ -701,11 +766,13 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
return true;
}
}
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error;
if (typeRecursionDetected)
- *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
+ error.setDescription(QDeclarativeImportDatabase::tr("is instantiated recursively"));
else
- *errorString = QDeclarativeImportDatabase::tr("is not a type");
+ error.setDescription(QDeclarativeImportDatabase::tr("is not a type"));
+ errors->prepend(error);
}
return false;
}
@@ -790,7 +857,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString)
+ QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
@@ -798,7 +865,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
<< (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File")
<< " as " << prefix;
- return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
+ return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors);
}
/*!
@@ -1013,7 +1080,7 @@ void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
@@ -1033,15 +1100,21 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
if (!engineInitialized || !typesRegistered) {
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(tr("File name case mismatch for \"%2\"").arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QPluginLoader loader(absoluteFilePath);
if (!loader.load()) {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
@@ -1063,8 +1136,11 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
iface->initializeEngine(engine, moduleId);
}
} else {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
}
diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h
index 1c910fd5bf..9d140bf106 100644
--- a/src/declarative/qml/qdeclarativeimport_p.h
+++ b/src/declarative/qml/qdeclarativeimport_p.h
@@ -84,7 +84,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
int *version_major, int *version_minor,
QDeclarativeImportedNamespace** ns_return,
- QString *errorString = 0) const;
+ QList<QDeclarativeError> *errors = 0) const;
bool resolveType(QDeclarativeImportedNamespace*,
const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return,
@@ -94,7 +94,7 @@ public:
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
void populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *) const;
@@ -110,7 +110,7 @@ public:
QDeclarativeImportDatabase(QDeclarativeEngine *);
~QDeclarativeImportDatabase();
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors);
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
diff --git a/src/declarative/qml/qdeclarativeinfo.cpp b/src/declarative/qml/qdeclarativeinfo.cpp
index 7c8f73bc61..8449578c65 100644
--- a/src/declarative/qml/qdeclarativeinfo.cpp
+++ b/src/declarative/qml/qdeclarativeinfo.cpp
@@ -129,6 +129,18 @@ QDeclarativeInfo::~QDeclarativeInfo()
int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
if (marker != -1)
typeName = typeName.left(marker);
+
+ marker = typeName.indexOf(QLatin1String("_QML_"));
+ if (marker != -1) {
+ typeName = typeName.left(marker) + "*";
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ if (type) {
+ typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ }
+ }
}
d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp
index 0c99cefb04..556b7bc343 100644
--- a/src/declarative/qml/qdeclarativeinstruction.cpp
+++ b/src/declarative/qml/qdeclarativeinstruction.cpp
@@ -96,6 +96,9 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
case QDeclarativeInstruction::StoreString:
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
break;
+ case QDeclarativeInstruction::StoreByteArray:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
+ break;
case QDeclarativeInstruction::StoreUrl:
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
break;
diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h
index 20be889252..a5521b6425 100644
--- a/src/declarative/qml/qdeclarativeinstruction_p.h
+++ b/src/declarative/qml/qdeclarativeinstruction_p.h
@@ -88,6 +88,7 @@ public:
// StoreInteger - Store a int or uint in a core property
// StoreBool - Store a bool in a core property
// StoreString - Store a QString in a core property
+ // StoreByteArray - Store a QByteArray in a core property
// StoreUrl - Store a QUrl in a core property
// StoreColor - Store a QColor in a core property
// StoreDate - Store a QDate in a core property
@@ -101,6 +102,7 @@ public:
StoreInteger, /* storeInteger */
StoreBool, /* storeBool */
StoreString, /* storeString */
+ StoreByteArray, /* storeByteArray */
StoreUrl, /* storeUrl */
StoreColor, /* storeColor */
StoreDate, /* storeDate */
@@ -245,6 +247,10 @@ public:
int propertyIndex;
int value;
};
+ struct StoreByteArrayInstruction {
+ int propertyIndex;
+ int value;
+ };
struct StoreScriptStringInstruction {
int propertyIndex;
int value;
@@ -332,6 +338,7 @@ public:
StoreIntegerInstruction storeInteger;
StoreBoolInstruction storeBool;
StoreStringInstruction storeString;
+ StoreByteArrayInstruction storeByteArray;
StoreScriptStringInstruction storeScriptString;
StoreScriptInstruction storeScript;
StoreUrlInstruction storeUrl;
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
index bf1f699c72..ede02e9f30 100644
--- a/src/declarative/qml/qdeclarativemetatype.cpp
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -88,6 +88,7 @@ QT_BEGIN_NAMESPACE
struct QDeclarativeMetaTypeData
{
+ QDeclarativeMetaTypeData();
~QDeclarativeMetaTypeData();
QList<QDeclarativeType *> types;
typedef QHash<int, QDeclarativeType *> Ids;
@@ -98,6 +99,14 @@ struct QDeclarativeMetaTypeData
MetaObjects metaObjectToType;
typedef QHash<int, QDeclarativeMetaType::StringConverter> StringConverters;
StringConverters stringConverters;
+ struct ModuleApiList {
+ ModuleApiList() : sorted(true) {}
+ QList<QDeclarativeMetaType::ModuleApi> moduleApis;
+ bool sorted;
+ };
+ typedef QHash<QByteArray, ModuleApiList> ModuleApis;
+ ModuleApis moduleApis;
+ int moduleApiCount;
struct ModuleInfo {
ModuleInfo(int major, int minor)
@@ -119,6 +128,11 @@ struct QDeclarativeMetaTypeData
Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData)
Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+QDeclarativeMetaTypeData::QDeclarativeMetaTypeData()
+: moduleApiCount(0)
+{
+}
+
QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData()
{
for (int i = 0; i < types.count(); ++i)
@@ -664,6 +678,34 @@ int registerType(const QDeclarativePrivate::RegisterType &type)
return index;
}
+int registerModuleApi(const QDeclarativePrivate::RegisterModuleApi &api)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QByteArray uri(api.uri);
+ QDeclarativeMetaType::ModuleApi import;
+ import.major = api.versionMajor;
+ import.minor = api.versionMinor;
+ import.script = api.scriptApi;
+ import.qobject = api.qobjectApi;
+
+ int index = data->moduleApiCount++;
+
+ QDeclarativeMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end()) {
+ QDeclarativeMetaTypeData::ModuleApiList apis;
+ apis.moduleApis << import;
+ data->moduleApis.insert(uri, apis);
+ } else {
+ iter->moduleApis << import;
+ iter->sorted = false;
+ }
+
+ return index;
+}
+
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
@@ -676,13 +718,16 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
} else if (type == AutoParentRegistration) {
return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
+ } else if (type == ModuleApiRegistration) {
+ return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
}
return -1;
}
/*
- Have any types been registered for \a module with at least versionMajor.versionMinor, and types
- for \a module with at most versionMajor.versionMinor.
+ Returns true if any type or API has been registered for the given \a module with at least
+ versionMajor.versionMinor, or if types have been registered for \a module with at most
+ versionMajor.versionMinor.
So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
@@ -691,13 +736,27 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
bool QDeclarativeMetaType::isModule(const QByteArray &module, int versionMajor, int versionMinor)
{
QDeclarativeMetaTypeData *data = metaTypeData();
+
+ // first, check Types
QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(module);
- return it != data->modules.end()
+ if (it != data->modules.end()
&& ((versionMajor<0 && versionMinor<0) ||
(((*it).vmajor_max > versionMajor ||
((*it).vmajor_max == versionMajor && (*it).vminor_max >= versionMinor))
&& ((*it).vmajor_min < versionMajor ||
- ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))));
+ ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))))) {
+ return true;
+ }
+
+ // then, check ModuleApis
+ foreach (const QDeclarativeMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
+ if ((versionMajor<0 && versionMinor<0)
+ || (mApi.major == versionMajor && mApi.minor == versionMinor)) {
+ return true;
+ }
+ }
+
+ return false;
}
QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunctions()
@@ -707,6 +766,35 @@ QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunct
return data->parentFunctions;
}
+static bool operator<(const QDeclarativeMetaType::ModuleApi &lhs, const QDeclarativeMetaType::ModuleApi &rhs)
+{
+ return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
+}
+
+QDeclarativeMetaType::ModuleApi
+QDeclarativeMetaType::moduleApi(const QByteArray &uri, int versionMajor, int versionMinor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end())
+ return ModuleApi();
+
+ if (iter->sorted == false) {
+ qSort(iter->moduleApis.begin(), iter->moduleApis.end());
+ iter->sorted = true;
+ }
+
+ for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
+ const ModuleApi &import = iter->moduleApis.at(ii);
+ if (import.major == versionMajor && import.minor <= versionMinor)
+ return import;
+ }
+
+ return ModuleApi();
+}
+
QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok)
{
if (!isQObject(v.userType())) {
diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h
index aab1c31ef5..291bc38222 100644
--- a/src/declarative/qml/qdeclarativemetatype_p.h
+++ b/src/declarative/qml/qdeclarativemetatype_p.h
@@ -59,6 +59,7 @@
#include <QtCore/qvariant.h>
#include <QtCore/qbitarray.h>
#include <private/qdeclarativeglobal_p.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,25 @@ public:
static bool isModule(const QByteArray &module, int versionMajor, int versionMinor);
static QList<QDeclarativePrivate::AutoParentFunction> parentFunctions();
+
+ struct ModuleApiInstance {
+ ModuleApiInstance()
+ : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {}
+
+ QScriptValue (*scriptCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QScriptValue scriptApi;
+ QObject *qobjectApi;
+ };
+ struct ModuleApi {
+ inline ModuleApi();
+ inline bool operator==(const ModuleApi &) const;
+ int major;
+ int minor;
+ QScriptValue (*script)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobject)(QDeclarativeEngine *, QScriptEngine *);
+ };
+ static ModuleApi moduleApi(const QByteArray &, int, int);
};
class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType
@@ -168,6 +188,25 @@ private:
QDeclarativeTypePrivate *d;
};
+QDeclarativeMetaType::ModuleApi::ModuleApi()
+// : major(0), minor(0), script(0), qobject(0)
+{
+ major = 0;
+ minor = 0;
+ script = 0;
+ qobject = 0;
+}
+
+bool QDeclarativeMetaType::ModuleApi::operator==(const ModuleApi &other) const
+{
+ return major == other.major && minor == other.minor && script == other.script && qobject == other.qobject;
+}
+
+inline uint qHash(const QDeclarativeMetaType::ModuleApi &import)
+{
+ return import.major ^ import.minor ^ quintptr(import.script) ^ quintptr(import.qobject);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEMETATYPE_P_H
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
index 9eecc65e3c..edc1755a72 100644
--- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
@@ -403,6 +403,33 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
} else if (value.isFunction() && !value.isRegExp()) {
// this is handled by the binding creation above
} else {
+ //### expand optimization for other known types
+ if (lastData->propType == QMetaType::Int && value.isNumber()) {
+ int rawValue = qRound(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QReal && value.isNumber()) {
+ qreal rawValue = qreal(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QString && value.isString()) {
+ const QString &rawValue = value.toString();
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ }
+
QVariant v;
if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h
index 7ac3369fc7..fea9eae109 100644
--- a/src/declarative/qml/qdeclarativeprivate.h
+++ b/src/declarative/qml/qdeclarativeprivate.h
@@ -74,6 +74,9 @@ public:
};
+class QScriptValue;
+class QScriptEngine;
+class QDeclarativeEngine;
class QDeclarativeCustomParser;
namespace QDeclarativePrivate
{
@@ -233,10 +236,22 @@ namespace QDeclarativePrivate
AutoParentFunction function;
};
+ struct RegisterModuleApi {
+ int version;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+
+ QScriptValue (*scriptApi)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectApi)(QDeclarativeEngine *, QScriptEngine *);
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
- AutoParentRegistration = 2
+ AutoParentRegistration = 2,
+ ModuleApiRegistration = 3,
};
int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index 6a39a65532..9cbb4fa8cc 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -61,6 +61,8 @@ QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsFor
flags |= Data::IsWritable;
if (p.isResettable())
flags |= Data::IsResettable;
+ if (p.isFinal())
+ flags |= Data::IsFinal;
if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
flags |= Data::IsQmlBinding;
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index eeeff1aea1..65a8725b8f 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -84,20 +84,21 @@ public:
IsWritable = 0x00000002,
IsResettable = 0x00000004,
IsAlias = 0x00000008,
+ IsFinal = 0x00000010,
// These are mutualy exclusive
- IsFunction = 0x00000010,
- IsQObjectDerived = 0x00000020,
- IsEnumType = 0x00000040,
- IsQList = 0x00000080,
- IsQmlBinding = 0x00000100,
- IsQScriptValue = 0x00000200,
+ IsFunction = 0x00000020,
+ IsQObjectDerived = 0x00000040,
+ IsEnumType = 0x00000080,
+ IsQList = 0x00000100,
+ IsQmlBinding = 0x00000200,
+ IsQScriptValue = 0x00000400,
// Apply only to IsFunctions
- IsVMEFunction = 0x00000400,
- HasArguments = 0x00000800,
- IsSignal = 0x00001000,
- IsVMESignal = 0x00002000
+ IsVMEFunction = 0x00000800,
+ HasArguments = 0x00001000,
+ IsSignal = 0x00002000,
+ IsVMESignal = 0x00004000
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
new file mode 100644
index 0000000000..121d0a1a35
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativetypenamescriptclass_p.h"
+#include "private/qdeclarativelistscriptclass_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativeguard_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtScript/qscriptcontextinfo.h>
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeScarceResourceScriptClass::QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *bindEngine)
+ : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // Properties of this type can be explicitly preserved by clients,
+ // which prevents the scarce resource from being automatically
+ // released after the binding has been evaluated.
+ m_preserve = scriptEngine->newFunction(preserve);
+ m_preserveId = createPersistentIdentifier(QLatin1String("preserve"));
+
+ // Similarly, they can be explicitly destroyed by clients,
+ // which releases the scarce resource.
+ m_destroy = scriptEngine->newFunction(destroy);
+ m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
+}
+
+QDeclarativeScarceResourceScriptClass::~QDeclarativeScarceResourceScriptClass()
+{
+}
+
+/*
+ Returns a JavaScript object whose instance data is a new scarce resource data.
+ The scarce resource is added to the doubly-linked-list of scarce resources in the engine
+ so that the scarce resource can be released after evaluation completes.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::newScarceResource(const QVariant &v)
+{
+ // create the scarce resource
+ ScarceResourceData *srd = new ScarceResourceData(v);
+
+ // insert into the linked list
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ srd->insertInto(&enginePrivate->scarceResources);
+ Q_ASSERT(enginePrivate->scarceResourcesRefCount > 0);
+
+ // return the javascript object with the scarce resource instance data
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, srd); // JSC takes ownership of srd.
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(Object *object, bool *ok)
+{
+ ScarceResourceData *obj = static_cast<ScarceResourceData*>(object);
+ if (ok) *ok = true;
+ return obj->resource;
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(const QScriptValue &value)
+{
+ Q_ASSERT(scriptClass(value) == this);
+
+ return toVariant(object(value), 0);
+}
+
+// The destroy() and preserve() function properties are readable.
+QScriptClass::QueryFlags
+QDeclarativeScarceResourceScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(object)
+ Q_UNUSED(flags)
+
+ if (name == m_destroyId.identifier || name == m_preserveId.identifier)
+ return (QScriptClass::HandlesReadAccess);
+ return 0;
+}
+
+// Return the (function) values which may be evaluated by clients.
+QDeclarativeScarceResourceScriptClass::Value
+QDeclarativeScarceResourceScriptClass::property(Object *object, const Identifier &name)
+{
+ Q_UNUSED(object)
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // functions
+ if (name == m_preserveId.identifier)
+ return Value(scriptEngine, m_preserve);
+ else if (name == m_destroyId.identifier)
+ return Value(scriptEngine, m_destroy);
+
+ return Value();
+}
+
+/*
+ The user explicitly wants to preserve the resource.
+ We remove the scarce resource from the engine's linked list
+ of resources to release after evaluation completes.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::preserve(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // The client wishes to preserve the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // remove node from list, without releasing the resource.
+ data->removeNode();
+
+ return engine->undefinedValue();
+}
+
+/*
+ The user explicitly wants to release the resource.
+ We set the internal scarce resource variant to the invalid variant.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // the client wishes to release the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // release the resource and remove the node from the list.
+ data->releaseResource();
+
+ return engine->undefinedValue();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
new file mode 100644
index 0000000000..2a1390a230
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
+#define QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+#include <QtScript/qscriptengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+
+/*
+ Scarce resources (like pixmaps and textures) are managed manually
+ in that the variant will be set to the invalid variant once the
+ JavaScript engine has finished using the JavaScript object whose
+ instance data is the ScarceResourceData (but before the garbage
+ collector frees the JavaScript object itself).
+
+ The engine stores a doubly-linked-list of scarce resources which
+ will to be cleaned up after a binding is successfully evaluated
+ (unless the user explicitly preserves the scarce resource).
+
+ A ScarceResourceData pointer should not be deleted manually, as
+ all instances of a ScarceResourceData should be owned by the
+ JavaScript engine.
+ */
+struct ScarceResourceData : public QScriptDeclarativeClass::Object {
+ ScarceResourceData(const QVariant &v) : resource(v), prev(0), next(0)
+ {
+ }
+
+ virtual ~ScarceResourceData()
+ {
+ releaseResource();
+ }
+
+ // Insert this resource into the given list of resources.
+ void insertInto(ScarceResourceData **list)
+ {
+ // This node becomes the head of the list.
+ next = *list; // so our next = old list head
+ *list = this; // list now points to us (we're the head)
+ prev = list; // as we're the head, our prev ptr becomes the list ptr.
+
+ // and the next node's prev pointer must contain a ptr to our next ptr,
+ // since per definition, prev always contains a pointer to the previous node's "next" ptr,
+ // and the "this" node is the "this->next" node's "prev" node.
+ if (next) next->prev = &next;
+ }
+
+ // Remove this resource from the list of resources, without releasing the resource.
+ void removeNode()
+ {
+ // whatever previously pointed to this node (ie, as that node's "next" node)
+ // should now point to our next node (since we no longer exist in the list).
+ // and the next node's prev ptr should point to our prev node.
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+ }
+
+ // Release this resource, and remove from the list.
+ void releaseResource()
+ {
+ resource = QVariant();
+ removeNode();
+ }
+
+ QVariant resource;
+
+ // prev always contains a pointer to the previous node's "next" ptr.
+ // :. for the head node, [*prev] will be engine->scarceResources
+ // :. for every other node, [*prev] will be the previous node's "next" ptr.
+ ScarceResourceData **prev;
+ ScarceResourceData *next;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScarceResourceScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeScarceResourceScriptClass();
+
+ // Creates a new JavaScript object whose instance data is the scarce resource v
+ QScriptValue newScarceResource(const QVariant &v);
+
+ // inherited from QScriptDeclarativeClass
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual QVariant toVariant(Object *, bool *ok = 0);
+ QVariant toVariant(const QScriptValue &value);
+
+private:
+ PersistentIdentifier m_preserveId;
+ PersistentIdentifier m_destroyId;
+ QScriptValue m_preserve;
+ QScriptValue m_destroy;
+
+ static QScriptValue preserve(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
+
+ QDeclarativeEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp
index e04cfc52af..352e341437 100644
--- a/src/declarative/qml/qdeclarativescriptparser.cpp
+++ b/src/declarative/qml/qdeclarativescriptparser.cpp
@@ -59,6 +59,22 @@ QT_BEGIN_NAMESPACE
using namespace QDeclarativeJS;
using namespace QDeclarativeParser;
+void QDeclarativeScriptParser::Import::extractVersion(int *maj, int *min) const
+{
+ *maj = -1; *min = -1;
+
+ if (!version.isEmpty()) {
+ int dot = version.indexOf(QLatin1Char('.'));
+ if (dot < 0) {
+ *maj = version.toInt();
+ *min = 0;
+ } else {
+ *maj = version.left(dot).toInt();
+ *min = version.mid(dot+1).toInt();
+ }
+ }
+}
+
namespace {
class ProcessAST: protected AST::Visitor
@@ -896,6 +912,19 @@ static void replaceWithSpace(QString &str, int idx, int n)
*data++ = space;
}
+static QDeclarativeParser::LocationSpan
+locationFromLexer(const QDeclarativeJS::Lexer &lex, int startLine, int startColumn, int startOffset)
+{
+ QDeclarativeParser::LocationSpan l;
+
+ l.start.line = startLine; l.start.column = startColumn;
+ l.end.line = lex.endLineNo(); l.end.column = lex.endColumnNo();
+ l.range.offset = startOffset;
+ l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset;
+
+ return l;
+}
+
/*
Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
are:
@@ -1024,7 +1053,8 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
return rv;
int startOffset = l.tokenOffset();
- int startLine = l.currentLineNo();
+ int startLine = l.startLineNo();
+ int startColumn = l.startColumnNo();
token = l.lex();
@@ -1062,8 +1092,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1072,9 +1105,9 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.type = Import::Script;
import.uri = file;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
-
} else {
// URI
QString uri;
@@ -1117,8 +1150,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1128,6 +1164,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.uri = uri;
import.version = version;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
}
@@ -1143,7 +1180,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
int endOffset = l.tokenLength() + l.tokenOffset();
- if (pragmaValue == QLatin1String("library")) {
+ if (pragmaValue == library) {
pragmas |= QDeclarativeParser::Object::ScriptBlock::Shared;
replaceWithSpace(script, startOffset, endOffset - startOffset);
} else {
diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h
index e5e0d7075d..fd89f757cc 100644
--- a/src/declarative/qml/qdeclarativescriptparser_p.h
+++ b/src/declarative/qml/qdeclarativescriptparser_p.h
@@ -82,6 +82,8 @@ public:
QString qualifier;
QString version;
+ void extractVersion(int *maj, int *min) const;
+
QDeclarativeParser::LocationSpan location;
};
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index 26f3996871..1c1eeee2cf 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -607,7 +607,7 @@ void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArra
if (!blob->isError() && !blob->isWaiting())
blob->allDependenciesDone();
- if (blob->status() != QDeclarativeDataBlob::Error)
+ if (blob->status() != QDeclarativeDataBlob::Error)
blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
blob->m_inCallback = false;
@@ -674,24 +674,23 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const
}
/*!
-Return a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached.
+Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached.
*/
-QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url)
+QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
{
Q_ASSERT(!url.isRelative() &&
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
- QDeclarativeScriptData *scriptData = m_scriptCache.value(url);
+ QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
- if (!scriptData) {
- scriptData = new QDeclarativeScriptData(url);
- m_scriptCache.insert(url, scriptData);
- QDeclarativeDataLoader::load(scriptData);
+ if (!scriptBlob) {
+ scriptBlob = new QDeclarativeScriptBlob(url, this);
+ m_scriptCache.insert(url, scriptBlob);
+ QDeclarativeDataLoader::load(scriptBlob);
}
- scriptData->addref();
- return scriptData;
+ return scriptBlob;
}
/*!
@@ -868,13 +867,14 @@ void QDeclarativeTypeData::dataReceived(const QByteArray &data)
}
} else if (import.type == QDeclarativeScriptParser::Import::Script) {
QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
- QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl);
- addDependency(data);
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
ScriptReference ref;
ref.location = import.location.start;
ref.qualifier = import.qualifier;
- ref.script = data;
+ ref.script = blob;
+ blob->addref();
m_scripts << ref;
}
@@ -933,14 +933,31 @@ void QDeclarativeTypeData::resolveTypes()
// For local urls, add an implicit import "." as first (most overridden) lookup.
// This will also trigger the loading of the qmldir and the import of any native
// types from available plugins.
+ QList<QDeclarativeError> errors;
if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- qmldir->dirComponents(), 0);
+ qmldir->dirComponents(), &errors);
} else {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- QDeclarativeDirComponents(), 0);
+ QDeclarativeDirComponents(), &errors);
+ }
+
+ // remove any errors which are due to the implicit import which aren't real errors.
+ // for example, if the implicitly included qmldir file doesn't exist, that is not an error.
+ QList<QDeclarativeError> realErrors;
+ for (int i = 0; i < errors.size(); ++i) {
+ if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace")
+ && errors.at(i).description() != QDeclarativeImportDatabase::tr("\".\": no such directory")) {
+ realErrors.prepend(errors.at(i)); // this is a real error.
+ }
+ }
+
+ // report any real errors which occurred during plugin loading or qmldir parsing.
+ if (!realErrors.isEmpty()) {
+ setError(realErrors);
+ return;
}
foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
@@ -950,34 +967,31 @@ void QDeclarativeTypeData::resolveTypes()
if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
- if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
+ if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
qmldircomponentsnetwork = qmldir->dirComponents();
}
int vmaj = -1;
int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
- if (!import.version.isEmpty()) {
- int dot = import.version.indexOf(QLatin1Char('.'));
- if (dot < 0) {
- vmaj = import.version.toInt();
- vmin = 0;
- } else {
- vmaj = import.version.left(dot).toInt();
- vmin = import.version.mid(dot+1).toInt();
- }
- }
-
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
- vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) {
+ vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
QDeclarativeError error;
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
error.setUrl(m_imports.baseUrl());
- error.setDescription(errorString);
error.setLine(import.location.start.line);
error.setColumn(import.location.start.column);
+ errors.prepend(error); // put it back on the list after filling out information.
- setError(error);
+ setError(errors);
return;
}
}
@@ -991,29 +1005,38 @@ void QDeclarativeTypeData::resolveTypes()
int majorVersion;
int minorVersion;
QDeclarativeImportedNamespace *typeNamespace = 0;
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
- &typeNamespace, &errorString) || typeNamespace) {
+ &typeNamespace, &errors) || typeNamespace) {
// Known to not be a type:
// - known to be a namespace (Namespace {})
// - type with unknown namespace (UnknownNamespace.SomeType {})
QDeclarativeError error;
- error.setUrl(m_imports.baseUrl());
QString userTypeName = parserRef->name;
userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
- if (typeNamespace)
+ if (typeNamespace) {
error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
- else
- error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
+ }
if (!parserRef->refObjects.isEmpty()) {
QDeclarativeParser::Object *obj = parserRef->refObjects.first();
error.setLine(obj->location.start.line);
error.setColumn(obj->location.start.column);
}
-
- setError(error);
+
+ errors.prepend(error);
+ setError(errors);
return;
}
@@ -1046,25 +1069,156 @@ QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
return 0;
}
-QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url)
-: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None)
+QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
+: QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_loaded(false)
+{
+}
+
+QDeclarativeScriptData::~QDeclarativeScriptData()
{
+ clear();
}
-QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const
+void QDeclarativeScriptData::clear()
+{
+ if (importCache) {
+ importCache->release();
+ importCache = 0;
+ }
+
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+ scripts.clear();
+}
+
+QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
+: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_scriptData(0), m_typeLoader(loader)
+{
+}
+
+QDeclarativeScriptBlob::~QDeclarativeScriptBlob()
+{
+ if (m_scriptData) {
+ m_scriptData->release();
+ m_scriptData = 0;
+ }
+}
+
+QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const
{
return m_pragmas;
}
-QString QDeclarativeScriptData::scriptSource() const
+QString QDeclarativeScriptBlob::scriptSource() const
{
return m_source;
}
-void QDeclarativeScriptData::dataReceived(const QByteArray &data)
+QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QDeclarativeImports &QDeclarativeScriptBlob::imports() const
+{
+ return m_imports;
+}
+
+QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
+ QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
+
m_source = QString::fromUtf8(data);
- m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source);
+
+ QDeclarativeScriptParser::JavaScriptMetaData metadata =
+ QDeclarativeScriptParser::extractMetaData(m_source);
+
+ m_imports.setBaseUrl(finalUrl());
+
+ m_pragmas = metadata.pragmas;
+
+ foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) {
+ Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File);
+
+ if (import.type == QDeclarativeScriptParser::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = blob;
+ blob->addref();
+ m_scripts << ref;
+ } else {
+ Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library);
+ int vmaj = -1;
+ int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
+
+ QList<QDeclarativeError> errors;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, QDeclarativeDirComponents(), &errors)) {
+ QDeclarativeError error = errors.takeFirst();
+ // description should be set by addImport().
+ error.setUrl(m_imports.baseUrl());
+ error.setLine(import.location.start.line);
+ error.setColumn(import.location.start.column);
+ errors.prepend(error);
+
+ setError(errors);
+ return;
+ }
+ }
+ }
+}
+
+void QDeclarativeScriptBlob::done()
+{
+ // Check all script dependencies for errors
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QDeclarativeError> errors = script.script->errors();
+ QDeclarativeError error;
+ error.setUrl(finalUrl());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString()));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ if (isError())
+ return;
+
+ QDeclarativeEngine *engine = typeLoader()->engine();
+ m_scriptData = new QDeclarativeScriptData(engine);
+ m_scriptData->url = finalUrl();
+ m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
+
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+
+ m_scriptData->scripts.append(script.script);
+ m_scriptData->importCache->add(script.qualifier, ii);
+ }
+
+ m_imports.populateCache(m_scriptData->importCache, engine);
+
+ m_scriptData->pragmas = m_pragmas;
+ m_scriptData->m_program = QScriptProgram(m_source, finalUrl().toString());
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index 7f487a0e24..1c0798d67b 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -55,8 +55,11 @@
#include <QtCore/qobject.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptprogram.h>
#include <QtDeclarative/qdeclarativeerror.h>
#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativecleanup_p.h>
#include <private/qdeclarativescriptparser_p.h>
#include <private/qdeclarativedirparser_p.h>
#include <private/qdeclarativeimport_p.h>
@@ -64,6 +67,7 @@
QT_BEGIN_NAMESPACE
class QDeclarativeScriptData;
+class QDeclarativeScriptBlob;
class QDeclarativeQmldirData;
class QDeclarativeTypeLoader;
class QDeclarativeCompiledData;
@@ -140,7 +144,7 @@ private:
QUrl m_finalUrl;
// List of QDeclarativeDataBlob's that are waiting for me to complete.
- QList<QDeclarativeDataBlob *> m_waitingOnMe;
+ QList<QDeclarativeDataBlob *> m_waitingOnMe;
// List of QDeclarativeDataBlob's that I am waiting for to complete.
QList<QDeclarativeDataBlob *> m_waitingFor;
@@ -178,7 +182,6 @@ private:
NetworkReplies m_networkReplies;
};
-
class Q_AUTOTEST_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader
{
Q_OBJECT
@@ -196,11 +199,11 @@ public:
QDeclarativeTypeData *get(const QByteArray &, const QUrl &url, Options = None);
void clearCache();
- QDeclarativeScriptData *getScript(const QUrl &);
+ QDeclarativeScriptBlob *getScript(const QUrl &);
QDeclarativeQmldirData *getQmldir(const QUrl &);
private:
typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
- typedef QHash<QUrl, QDeclarativeScriptData *> ScriptCache;
+ typedef QHash<QUrl, QDeclarativeScriptBlob *> ScriptCache;
typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache;
TypeCache m_typeCache;
@@ -230,7 +233,7 @@ public:
QDeclarativeParser::Location location;
QString qualifier;
- QDeclarativeScriptData *script;
+ QDeclarativeScriptBlob *script;
};
QDeclarativeTypeData(const QUrl &, QDeclarativeTypeLoader::Options, QDeclarativeTypeLoader *);
@@ -285,20 +288,65 @@ private:
QDeclarativeTypeLoader *m_typeLoader;
};
-class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeDataBlob
+class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeRefCount, public QDeclarativeCleanup
{
public:
- QDeclarativeScriptData(const QUrl &);
+ QDeclarativeScriptData(QDeclarativeEngine *);
+ ~QDeclarativeScriptData();
+
+ QUrl url;
+ QDeclarativeTypeNameCache *importCache;
+ QList<QDeclarativeScriptBlob *> scripts;
+ QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas;
+
+protected:
+ virtual void clear(); // From QDeclarativeCleanup
+
+private:
+ friend class QDeclarativeVME;
+ friend class QDeclarativeScriptBlob;
+
+ bool m_loaded;
+ QScriptProgram m_program;
+ QScriptValue m_value;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
+{
+public:
+ QDeclarativeScriptBlob(const QUrl &, QDeclarativeTypeLoader *);
+ ~QDeclarativeScriptBlob();
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QDeclarativeParser::Location location;
+ QString qualifier;
+ QDeclarativeScriptBlob *script;
+ };
QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas() const;
QString scriptSource() const;
+ QDeclarativeTypeLoader *typeLoader() const;
+ const QDeclarativeImports &imports() const;
+
+ QDeclarativeScriptData *scriptData() const;
+
protected:
virtual void dataReceived(const QByteArray &);
+ virtual void done();
private:
QDeclarativeParser::Object::ScriptBlock::Pragmas m_pragmas;
QString m_source;
+
+ QDeclarativeImports m_imports;
+ QList<ScriptReference> m_scripts;
+ QDeclarativeScriptData *m_scriptData;
+
+ QDeclarativeTypeLoader *m_typeLoader;
};
class Q_AUTOTEST_EXPORT QDeclarativeQmldirData : public QDeclarativeDataBlob
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
index 48c72a7fef..b9577c17fa 100644
--- a/src/declarative/qml/qdeclarativetypenamecache.cpp
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+: QDeclarativeCleanup(e), engine(e), m_moduleApi(0)
{
}
@@ -60,6 +60,7 @@ void QDeclarativeTypeNameCache::clear()
qDeleteAll(stringCache);
stringCache.clear();
identifierCache.clear();
+ m_moduleApi = 0;
engine = 0;
}
@@ -114,5 +115,10 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &
return stringCache.value(id);
}
+void QDeclarativeTypeNameCache::setModuleApi(QDeclarativeMetaType::ModuleApiInstance *api)
+{
+ m_moduleApi = api;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index f2562da777..bcca41f4d5 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -55,6 +55,7 @@
#include "private/qdeclarativerefcount_p.h"
#include "private/qdeclarativecleanup_p.h"
+#include "private/qdeclarativemetatype_p.h"
#include <private/qscriptdeclarativeclass_p.h>
@@ -82,6 +83,10 @@ public:
Data *data(const QString &) const;
inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+ inline bool isEmpty() const;
+
+ inline QDeclarativeMetaType::ModuleApiInstance *moduleApi() const;
+ void setModuleApi(QDeclarativeMetaType::ModuleApiInstance *);
protected:
virtual void clear();
@@ -96,6 +101,7 @@ private:
StringCache stringCache;
IdentifierCache identifierCache;
QDeclarativeEngine *engine;
+ QDeclarativeMetaType::ModuleApiInstance *m_moduleApi;
};
QDeclarativeTypeNameCache::Data::Data()
@@ -113,6 +119,16 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDe
return identifierCache.value(id);
}
+bool QDeclarativeTypeNameCache::isEmpty() const
+{
+ return identifierCache.isEmpty();
+}
+
+QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi() const
+{
+ return m_moduleApi;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVETYPENAMECACHE_P_H
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
index a7c0b2cfbe..d628b7065a 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
@@ -63,7 +63,7 @@ struct TypeNameData : public QScriptDeclarativeClass::Object {
QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine), object(0), type(0)
+ engine(bindEngine), object(0), type(0), api(0)
{
}
@@ -95,14 +95,35 @@ QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &na
object = 0;
type = 0;
+ api = 0;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
if (data->typeNamespace) {
-
QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name);
if (d && d->type) {
type = d->type;
return QScriptClass::HandlesReadAccess;
+ } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = data->typeNamespace->moduleApi()) {
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ api = moduleApi;
+ if (api->qobjectApi) {
+ return ep->objectClass->queryProperty(api->qobjectApi, name, flags, 0,
+ QDeclarativeObjectScriptClass::SkipAttachedProperties);
+ } else {
+ return QScriptClass::HandlesReadAccess;
+ }
+
+ return 0;
+
} else {
return 0;
}
@@ -147,6 +168,10 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
} else if (object) {
return ep->objectClass->property(object, name);
+ } else if (api && api->qobjectApi) {
+ return ep->objectClass->property(api->qobjectApi, name);
+ } else if (api) {
+ return propertyValue(api->scriptApi, name);
} else {
return Value(scriptEngine, enumValue);
}
@@ -154,11 +179,16 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v)
{
- Q_ASSERT(object);
Q_ASSERT(!type);
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- ep->objectClass->setProperty(object, n, v, context());
+ if (api) {
+ Q_ASSERT(api->qobjectApi);
+ ep->objectClass->setProperty(api->qobjectApi, n, v, context());
+ } else {
+ Q_ASSERT(object);
+ ep->objectClass->setProperty(object, n, v, context());
+ }
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
index cf7dbc8480..49e1ae809e 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
@@ -83,6 +83,7 @@ private:
QDeclarativeEngine *engine;
QObject *object;
QDeclarativeType *type;
+ QDeclarativeMetaType::ModuleApiInstance *api;
quint32 enumValue;
};
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 781e1b8ea3..6bbc47bcaf 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -57,8 +57,9 @@
#include "private/qdeclarativevmemetaobject_p.h"
#include "private/qdeclarativebinding_p_p.h"
#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include <QStack>
@@ -71,6 +72,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdatetime.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -158,7 +160,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
const QList<int> &intData = comp->intData;
const QList<float> &floatData = comp->floatData;
const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches;
- const QList<QDeclarativeParser::Object::ScriptBlock> &scripts = comp->scripts;
+ const QList<QDeclarativeScriptData *> &scripts = comp->scripts;
const QList<QUrl> &urls = comp->urls;
QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues;
@@ -186,7 +188,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
if (instr.init.contextCache != -1)
ctxt->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache));
if (instr.init.compiledBinding != -1)
- ctxt->optimizedBindings = new QDeclarativeCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
+ ctxt->optimizedBindings = new QDeclarativeV4Bindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
}
break;
@@ -409,6 +411,15 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
}
break;
+ case QDeclarativeInstruction::StoreByteArray:
+ {
+ QObject *target = stack.top();
+ void *a[] = { (void *)&datas.at(instr.storeByteArray.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeByteArray.propertyIndex, a);
+ }
+ break;
+
case QDeclarativeInstruction::StoreUrl:
{
QObject *target = stack.top();
@@ -701,7 +712,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreImportedScript:
{
- ctxt->addImportedScript(scripts.at(instr.storeScript.value));
+ ctxt->importedScripts << run(ctxt, scripts.at(instr.storeScript.value));
}
break;
@@ -1054,5 +1065,68 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData
}
}
+QScriptValue QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
+{
+ if (script->m_loaded)
+ return script->m_value;
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentCtxt->engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(parentCtxt->engine);
+
+ bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
+
+ // Create the script context if required
+ QDeclarativeContextData *ctxt = 0;
+ if (!shared) {
+ ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->url = script->url;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!script->importCache->isEmpty()) {
+ ctxt->imports = script->importCache;
+ } else {
+ ctxt->imports = parentCtxt->imports;
+ }
+
+ if (ctxt->imports) {
+ ctxt->imports->addref();
+ }
+
+ ctxt->setParent(parentCtxt, true);
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii)
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ }
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ if (shared) {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(script->url.toString())); // XXX toString()?
+ } else {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(ctxt, 0, script->url.toString()));
+ }
+
+ scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
+ scriptContext->pushScope(scope);
+
+ scriptEngine->evaluate(script->m_program);
+
+ if (scriptEngine->hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+ enginePriv->warning(error);
+ }
+
+ scriptEngine->popContext();
+
+ if (shared) {
+ script->m_loaded = true;
+ script->m_value = scope;
+ }
+
+ return scope;
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index 77c016c1a8..4c010f19d8 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -62,6 +62,8 @@
QT_BEGIN_NAMESPACE
class QObject;
+class QScriptValue;
+class QDeclarativeScriptData;
class QDeclarativeInstruction;
class QDeclarativeCompiledData;
class QDeclarativeCompiledData;
@@ -103,6 +105,8 @@ public:
QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
int start = -1, int count = -1,
const QBitField & = QBitField());
+ QScriptValue run(QDeclarativeContextData *, QDeclarativeScriptData *);
+
void runDeferred(QObject *);
bool isError() const;
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index ad1bf0dd3a..6eb74b3bad 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -647,6 +647,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
return -1; // We can't run the method
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
QScriptValue function = method(id);
@@ -657,10 +658,19 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
}
}
+
QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
+ if (ep->scriptEngine.hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(&ep->scriptEngine, error);
+ if (error.isValid()) {
+ ep->warning(error);
+ }
+ }
if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return -1;
}
return -1;
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
index aefc896f5b..930d345285 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -101,6 +101,8 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+namespace {
+
class DocumentImpl;
class NodeImpl
{
@@ -323,6 +325,8 @@ public:
static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
};
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Node)
@@ -1231,6 +1235,18 @@ void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
}
}
+static const char *errorToString(QNetworkReply::NetworkError error)
+{
+ int idx = QNetworkReply::staticMetaObject.indexOfEnumerator("NetworkError");
+ if (idx == -1) return "EnumLookupFailed";
+
+ QMetaEnum e = QNetworkReply::staticMetaObject.enumerator(idx);
+
+ const char *name = e.valueToKey(error);
+ if (!name) return "EnumLookupFailed";
+ else return name;
+}
+
void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
@@ -1245,6 +1261,11 @@ void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
m_data.clear();
destroyNetwork();
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: ERROR " << qPrintable(m_url.toString());
+ qWarning().nospace() << " " << error << " " << errorToString(error) << " " << m_statusText;
+ }
+
if (error == QNetworkReply::ContentAccessDenied ||
error == QNetworkReply::ContentOperationNotPermittedError ||
error == QNetworkReply::ContentNotFoundError ||
diff --git a/src/declarative/qml/qintrusivelist.cpp b/src/declarative/qml/qintrusivelist.cpp
new file mode 100644
index 0000000000..6c27af0777
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qintrusivelist_p.h"
+
+/*!
+\class QIntrusiveList
+\brief The QIntrusiveList class is a template class that provides a list of objects using static storage.
+\internal
+
+QIntrusiveList creates a linked list of objects. Adding and removing objects from the
+QIntrusiveList is a constant time operation and is very quick. The list performs no memory
+allocations, but does require the objects being added to the list to contain a QIntrusiveListNode
+instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's
+other list classes.
+
+As QIntrusiveList uses storage inside the objects in the list, each object can only be in one
+list at a time. Objects are inserted by the insert() method. If the object is already
+in a list (including the one it is being inserted into) it is first removed, and then inserted
+at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an
+insert() the inserted object becomes the list's first() object.
+
+\code
+struct MyObject {
+ MyObject(int value) : value(value) {}
+
+ int value;
+ QIntrusiveListNode node;
+};
+typedef QIntrusiveList<MyObject, &MyObject::node> MyObjectList;
+
+void foo() {
+ MyObjectList list;
+
+ MyObject m0(0);
+ MyObject m1(1);
+ MyObject m2(2);
+
+ list.insert(&m0);
+ list.insert(&m1);
+ list.insert(&m2);
+
+ // QIntrusiveList is LIFO, so will print: 2... 1... 0...
+ for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ qWarning() << iter->value;
+ }
+}
+\endcode
+*/
+
+
+/*!
+\fn QIntrusiveList::QIntrusiveList();
+
+Construct an empty list.
+*/
+
+/*!
+\fn QIntrusiveList::~QIntrusiveList();
+
+Destroy the list. All entries are removed.
+*/
+
+/*!
+\fn void QIntrusiveList::insert(N *object);
+
+Insert \a object into the list. If \a object is a member of this, or another list, it will be
+removed and inserted at the head of this list.
+*/
+
+/*!
+\fn void QIntrusiveList::remove(N *object);
+
+Remove \a object from the list. \a object must not be null.
+*/
+
+/*!
+\fn N *QIntrusiveList::first() const
+
+Returns the first entry in this list, or null if the list is empty.
+*/
+
+/*!
+\fn N *QIntrusiveList::next(N *current)
+
+Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null.
+*/
+
+/*!
+\fn iterator QIntrusiveList::begin()
+
+Returns an STL-style interator pointing to the first item in the list.
+
+\sa end()
+*/
+
+/*!
+\fn iterator QIntrusiveList::end()
+
+Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
+
+\sa begin()
+*/
+
+/*!
+iterator &QInplacelist::iterator::erase()
+
+Remove the current object from the list, and return an iterator to the next element.
+*/
+
+
+/*!
+\fn QIntrusiveListNode::QIntrusiveListNode()
+
+Create a QIntrusiveListNode.
+*/
+
+/*!
+\fn QIntrusiveListNode::~QIntrusiveListNode()
+
+Destroy the QIntrusiveListNode. If the node is in a list, it is removed.
+*/
+
+/*!
+\fn void QIntrusiveListNode::remove()
+
+If in a list, remove this node otherwise do nothing.
+*/
+
+/*!
+\fn bool QIntrusiveListNode::isInList() const
+
+Returns true if this node is in a list, false otherwise.
+*/
+
diff --git a/src/declarative/qml/qintrusivelist_p.h b/src/declarative/qml/qintrusivelist_p.h
new file mode 100644
index 0000000000..459d051d07
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist_p.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINTRUSIVELIST_P_H
+#define QINTRUSIVELIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIntrusiveListNode;
+template<class N, QIntrusiveListNode N::*member>
+class QIntrusiveList
+{
+public:
+ inline QIntrusiveList();
+ inline ~QIntrusiveList();
+
+ inline void insert(N *n);
+ inline void remove(N *n);
+
+ class iterator {
+ public:
+ inline iterator();
+ inline iterator(N *value);
+
+ inline N *operator*() const;
+ inline N *operator->() const;
+ inline bool operator==(const iterator &other) const;
+ inline bool operator!=(const iterator &other) const;
+ inline iterator &operator++();
+
+ inline iterator &erase();
+
+ private:
+ N *_value;
+ };
+ typedef iterator Iterator;
+
+ inline N *first() const;
+ static inline N *next(N *current);
+
+ inline iterator begin();
+ inline iterator end();
+
+private:
+ static inline N *nodeToN(QIntrusiveListNode *node);
+
+ QIntrusiveListNode *__first;
+};
+
+class QIntrusiveListNode
+{
+public:
+ inline QIntrusiveListNode();
+ inline ~QIntrusiveListNode();
+
+ inline void remove();
+ inline bool isInList() const;
+
+ QIntrusiveListNode *_next;
+ QIntrusiveListNode**_prev;
+};
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator()
+: _value(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator(N *value)
+: _value(value)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator*() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator->() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
+{
+ return other._value == _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
+{
+ return other._value != _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
+{
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+{
+ N *old = _value;
+ _value = QIntrusiveList<N, member>::next(_value);
+ (old->*member).remove();
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::QIntrusiveList()
+: __first(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::~QIntrusiveList()
+{
+ while (__first) __first->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::insert(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::remove(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::first() const
+{
+ return __first?nodeToN(__first):0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::next(N *current)
+{
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ N *nextstruct = nextnode?nodeToN(nextnode):0;
+ return nextstruct;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
+{
+ return __first?iterator(nodeToN(__first)):iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
+{
+ return iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
+{
+ return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0));
+}
+
+QIntrusiveListNode::QIntrusiveListNode()
+: _next(0), _prev(0)
+{
+}
+
+QIntrusiveListNode::~QIntrusiveListNode()
+{
+ remove();
+}
+
+void QIntrusiveListNode::remove()
+{
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = 0;
+ _next = 0;
+}
+
+bool QIntrusiveListNode::isInList() const
+{
+ return _prev != 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QINTRUSIVELIST_P_H
diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp
index dc941e2601..a63656bc28 100644
--- a/src/declarative/qml/qmetaobjectbuilder.cpp
+++ b/src/declarative/qml/qmetaobjectbuilder.cpp
@@ -101,7 +101,7 @@ bool isVariantType(const char* type)
return qvariant_nameToType(type) != 0;
}
-// copied from qmetaobject.cpp
+// copied from qmetaobject_p.h
// do not touch without touching the moc as well
enum PropertyFlags {
Invalid = 0x00000000,
@@ -111,6 +111,8 @@ enum PropertyFlags {
EnumOrFlag = 0x00000008,
StdCppSet = 0x00000100,
// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
Designable = 0x00001000,
ResolveDesignable = 0x00002000,
Scriptable = 0x00004000,
@@ -618,6 +620,8 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
property.setUser(prototype.isUser());
property.setStdCppSet(prototype.hasStdCppSet());
property.setEnumOrFlag(prototype.isEnumType());
+ property.setConstant(prototype.isConstant());
+ property.setFinal(prototype.isFinal());
if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one.
QMetaMethod method = prototype.notifySignal();
@@ -2278,6 +2282,32 @@ bool QMetaPropertyBuilder::isEnumOrFlag() const
}
/*!
+ Returns true if the property is constant; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isConstant() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Constant);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is final; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isFinal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Final);
+ else
+ return false;
+}
+
+/*!
Sets this property to readable if \a value is true.
\sa isReadable(), setWritable()
@@ -2401,6 +2431,31 @@ void QMetaPropertyBuilder::setEnumOrFlag(bool value)
}
/*!
+ Sets the \c CONSTANT flag on this property to \a value.
+
+ \sa isConstant()
+*/
+void QMetaPropertyBuilder::setConstant(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Constant, value);
+}
+
+/*!
+ Sets the \c FINAL flag on this property to \a value.
+
+ \sa isFinal()
+*/
+void QMetaPropertyBuilder::setFinal(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Final, value);
+}
+
+
+/*!
\class QMetaEnumBuilder
\internal
\brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h
index d7085f8784..335a825be3 100644
--- a/src/declarative/qml/qmetaobjectbuilder_p.h
+++ b/src/declarative/qml/qmetaobjectbuilder_p.h
@@ -258,6 +258,8 @@ public:
bool isUser() const;
bool hasStdCppSet() const;
bool isEnumOrFlag() const;
+ bool isConstant() const;
+ bool isFinal() const;
void setReadable(bool value);
void setWritable(bool value);
@@ -269,6 +271,8 @@ public:
void setUser(bool value);
void setStdCppSet(bool value);
void setEnumOrFlag(bool value);
+ void setConstant(bool value);
+ void setFinal(bool value);
private:
const QMetaObjectBuilder *_mobj;
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index bf9e54a986..62c1f97d60 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -18,7 +18,6 @@ SOURCES += \
$$PWD/qdeclarativecompiler.cpp \
$$PWD/qdeclarativecompileddata.cpp \
$$PWD/qdeclarativeboundsignal.cpp \
- $$PWD/qdeclarativedom.cpp \
$$PWD/qdeclarativerefcount.cpp \
$$PWD/qdeclarativemetatype.cpp \
$$PWD/qdeclarativestringconverters.cpp \
@@ -30,7 +29,6 @@ SOURCES += \
$$PWD/qdeclarativeenginedebug.cpp \
$$PWD/qdeclarativerewrite.cpp \
$$PWD/qdeclarativevaluetype.cpp \
- $$PWD/qdeclarativecompiledbindings.cpp \
$$PWD/qdeclarativefastproperties.cpp \
$$PWD/qdeclarativexmlhttprequest.cpp \
$$PWD/qdeclarativesqldatabase.cpp \
@@ -44,6 +42,7 @@ SOURCES += \
$$PWD/qdeclarativetypenamecache.cpp \
$$PWD/qdeclarativescriptstring.cpp \
$$PWD/qdeclarativeobjectscriptclass.cpp \
+ $$PWD/qdeclarativescarceresourcescriptclass.cpp \
$$PWD/qdeclarativecontextscriptclass.cpp \
$$PWD/qdeclarativeglobalscriptclass.cpp \
$$PWD/qdeclarativevaluetypescriptclass.cpp \
@@ -56,7 +55,8 @@ SOURCES += \
$$PWD/qdeclarativeextensionplugin.cpp \
$$PWD/qdeclarativeimport.cpp \
$$PWD/qdeclarativelist.cpp \
- $$PWD/qperformancetimer.cpp
+ $$PWD/qperformancetimer.cpp \
+ $$PWD/qintrusivelist.cpp \
HEADERS += \
$$PWD/qdeclarativeparser_p.h \
@@ -81,8 +81,6 @@ HEADERS += \
$$PWD/qdeclarativeengine_p.h \
$$PWD/qdeclarativeexpression_p.h \
$$PWD/qdeclarativeprivate.h \
- $$PWD/qdeclarativedom_p.h \
- $$PWD/qdeclarativedom_p_p.h \
$$PWD/qdeclarativerefcount_p.h \
$$PWD/qdeclarativemetatype_p.h \
$$PWD/qdeclarativeengine.h \
@@ -104,7 +102,6 @@ HEADERS += \
$$PWD/qpodvector_p.h \
$$PWD/qbitfield_p.h \
$$PWD/qdeclarativevaluetype_p.h \
- $$PWD/qdeclarativecompiledbindings_p.h \
$$PWD/qdeclarativefastproperties_p.h \
$$PWD/qdeclarativexmlhttprequest_p.h \
$$PWD/qdeclarativesqldatabase_p.h \
@@ -118,6 +115,7 @@ HEADERS += \
$$PWD/qdeclarativetypenamecache_p.h \
$$PWD/qdeclarativescriptstring.h \
$$PWD/qdeclarativeobjectscriptclass_p.h \
+ $$PWD/qdeclarativescarceresourcescriptclass_p.h \
$$PWD/qdeclarativecontextscriptclass_p.h \
$$PWD/qdeclarativeglobalscriptclass_p.h \
$$PWD/qdeclarativevaluetypescriptclass_p.h \
@@ -131,11 +129,13 @@ HEADERS += \
$$PWD/qdeclarativeextensioninterface.h \
$$PWD/qdeclarativeimport_p.h \
$$PWD/qdeclarativeextensionplugin.h \
- $$PWD/qperformancetimer_p.h
+ $$PWD/qperformancetimer_p.h \
+ $$PWD/qintrusivelist_p.h \
QT += sql
include(parser/parser.pri)
include(rewriter/rewriter.pri)
+include(v4/v4.pri)
# mirrors logic in corelib/kernel/kernel.pri
unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
new file mode 100644
index 0000000000..80c7a68697
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -0,0 +1,1530 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define REGISTER_CLEANUP_DEBUG
+
+#include "private/qdeclarativev4bindings_p.h"
+#include "private/qdeclarativev4program_p.h"
+#include "private/qdeclarativev4compiler_p.h"
+
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativedebugtrace_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <math.h> // ::fmod
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+namespace {
+struct Register {
+ typedef QDeclarativeRegisterType Type;
+
+ void setUndefined() { dataType = UndefinedType; }
+ void setNaN() { setqreal(qSNaN()); }
+ bool isUndefined() const { return dataType == UndefinedType; }
+
+ void setQObject(QObject *o) { *((QObject **)data) = o; dataType = QObjectStarType; }
+ QObject *getQObject() const { return *((QObject **)data); }
+
+ void setqreal(qreal v) { *((qreal *)data) = v; dataType = QRealType; }
+ qreal getqreal() const { return *((qreal *)data); }
+ qreal &getqrealref() const { return *((qreal *)data); }
+
+ void setint(int v) { *((int *)data) = v; dataType = IntType; }
+ int getint() const { return *((int *)data); }
+ int &getintref() const { return *((int *)data); }
+
+ void setbool(bool v) { *((bool *)data) = v; dataType = BoolType; }
+ bool getbool() const { return *((bool *)data); }
+ bool &getboolref() const { return *((bool *)data); }
+
+ QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
+ QString *getstringptr() { return (QString *)typeDataPtr(); }
+ QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
+ const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
+ const QString *getstringptr() const { return (QString *)typeDataPtr(); }
+ const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+
+ void *typeDataPtr() { return (void *)&data; }
+ void *typeMemory() { return (void *)data; }
+ const void *typeDataPtr() const { return (void *)&data; }
+ const void *typeMemory() const { return (void *)data; }
+
+ Type gettype() const { return dataType; }
+ void settype(Type t) { dataType = t; }
+
+ // int type; // Optional type
+
+ Type dataType; // Type of data
+ void *data[2]; // Object stored here
+
+ inline void cleanup();
+ inline void cleanupString();
+ inline void cleanupUrl();
+ inline void cleanupVariant();
+
+ inline void copy(const Register &other);
+ inline void init(Type type);
+#ifdef REGISTER_CLEANUP_DEBUG
+ Register() {
+ type = 0;
+ }
+
+ ~Register() {
+ if (dataType >= FirstCleanupType)
+ qWarning("Register leaked of type %d", dataType);
+ }
+#endif
+};
+
+void Register::cleanup()
+{
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType) {
+ getstringptr()->~QString();
+ } else if (dataType == QUrlType) {
+ geturlptr()->~QUrl();
+ } else if (dataType == QVariantType) {
+ getvariantptr()->~QVariant();
+ }
+ }
+ setUndefined();
+}
+
+void Register::cleanupString()
+{
+ getstringptr()->~QString();
+ setUndefined();
+}
+
+void Register::cleanupUrl()
+{
+ geturlptr()->~QUrl();
+ setUndefined();
+}
+
+void Register::cleanupVariant()
+{
+ getvariantptr()->~QVariant();
+ setUndefined();
+}
+
+void Register::copy(const Register &other)
+{
+ *this = other;
+ if (other.dataType >= FirstCleanupType) {
+ if (other.dataType == QStringType)
+ new (getstringptr()) QString(*other.getstringptr());
+ else if (other.dataType == QUrlType)
+ new (geturlptr()) QUrl(*other.geturlptr());
+ else if (other.dataType == QVariantType)
+ new (getvariantptr()) QVariant(*other.getvariantptr());
+ }
+}
+
+void Register::init(Type type)
+{
+ dataType = type;
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType)
+ new (getstringptr()) QString();
+ else if (dataType == QUrlType)
+ new (geturlptr()) QUrl();
+ else if (dataType == QVariantType)
+ new (getvariantptr()) QVariant();
+ }
+}
+
+} // end of anonymous namespace
+
+class QDeclarativeV4BindingsPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeV4Bindings)
+
+public:
+ QDeclarativeV4BindingsPrivate();
+ virtual ~QDeclarativeV4BindingsPrivate();
+
+ struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
+ Binding() : enabled(false), updating(0), property(0),
+ scope(0), target(0), executedBlocks(0), parent(0) {}
+
+ // Inherited from QDeclarativeAbstractBinding
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void destroy();
+
+ int index:30;
+ bool enabled:1;
+ bool updating:1;
+ int property;
+ QObject *scope;
+ QObject *target;
+ quint32 executedBlocks;
+
+ QDeclarativeV4BindingsPrivate *parent;
+ };
+
+ typedef QDeclarativeNotifierEndpoint Subscription;
+ Subscription *subscriptions;
+ QScriptDeclarativeClass::PersistentIdentifier *identifiers;
+
+ void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
+
+ QDeclarativeV4Program *program;
+ Binding *bindings;
+
+ static int methodCount;
+
+ void init();
+ void run(int instr, quint32 &executedBlocks, QDeclarativeContextData *context,
+ QDeclarativeDelayedError *error, QObject *scope, QObject *output,
+ QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ , void ***decode_instr = 0
+#endif
+ );
+
+
+ inline void unsubscribe(int subIndex);
+ inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
+ inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+
+ inline static qint32 toInt32(qsreal n);
+ static const qsreal D32;
+ static quint32 toUint32(qsreal n);
+};
+
+QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate()
+: subscriptions(0), identifiers(0), program(0), bindings(0)
+{
+}
+
+QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate()
+{
+ delete [] subscriptions; subscriptions = 0;
+ delete [] identifiers; identifiers = 0;
+}
+
+int QDeclarativeV4BindingsPrivate::methodCount = -1;
+
+QDeclarativeV4Bindings::QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context)
+: QObject(*(new QDeclarativeV4BindingsPrivate))
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (d->methodCount == -1)
+ d->methodCount = QDeclarativeV4Bindings::staticMetaObject.methodCount();
+
+ d->program = (QDeclarativeV4Program *)program;
+
+ if (program) {
+ d->init();
+
+ QDeclarativeAbstractExpression::setContext(context);
+ }
+}
+
+QDeclarativeV4Bindings::~QDeclarativeV4Bindings()
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ delete [] d->bindings;
+}
+
+QDeclarativeAbstractBinding *QDeclarativeV4Bindings::configBinding(int index, QObject *target,
+ QObject *scope, int property)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Binding *rv = d->bindings + index;
+
+ rv->index = index;
+ rv->property = property;
+ rv->target = target;
+ rv->scope = scope;
+ rv->parent = d;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (enabled != e) {
+ enabled = e;
+
+ if (e) update(flags);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
+ parent->run(this, flags);
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::destroy()
+{
+ enabled = false;
+ removeFromObject();
+ clear();
+ parent->q_func()->release();
+}
+
+int QDeclarativeV4Bindings::qt_metacall(QMetaObject::Call c, int id, void **)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
+ id -= d->methodCount;
+
+ QDeclarativeV4Program::BindingReferenceList *list = d->program->signalTable(id);
+
+ for (quint32 ii = 0; ii < list->count; ++ii) {
+ QDeclarativeV4Program::BindingReference *bindingRef = list->bindings + ii;
+
+ QDeclarativeV4BindingsPrivate::Binding *binding = d->bindings + bindingRef->binding;
+ if (binding->executedBlocks & bindingRef->blockMask)
+ d->run(binding, QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+ return -1;
+}
+
+void QDeclarativeV4BindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ if (!binding->enabled)
+ return;
+
+ QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
+ if (!context || !context->isValid())
+ return;
+
+ if (binding->updating) {
+ QString name;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+
+ name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
+ name.append(QLatin1String("."));
+ name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
+ } else {
+ name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
+ }
+ qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeV4Bindings", "Binding loop detected for property \"%1\"").arg(name);
+ return;
+ }
+
+ binding->updating = true;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+ vt->read(binding->target, binding->property & 0xFFFF);
+
+ QObject *target = vt;
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
+
+ vt->write(binding->target, binding->property & 0xFFFF, flags);
+ } else {
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
+ }
+ binding->updating = false;
+}
+
+
+void QDeclarativeV4BindingsPrivate::unsubscribe(int subIndex)
+{
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->disconnect();
+}
+
+void QDeclarativeV4BindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ unsubscribe(subIndex);
+
+ if (p->idValues[idIndex]) {
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIndex;
+ sub->connect(&p->idValues[idIndex].bindings);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIndex;
+ if (o)
+ sub->connect(o, notifyIndex);
+ else
+ sub->disconnect();
+}
+
+// Conversion functions - these MUST match the QtScript expression path
+inline static qreal toReal(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return reg->getqreal();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toReal();
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+inline static QString toString(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return QString::number(reg->getqreal());
+ } else if (type == QMetaType::Int) {
+ return QString::number(reg->getint());
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toString();
+ } else if (type == QMetaType::QString) {
+ return *reg->getstringptr();
+ } else {
+ if (ok) *ok = false;
+ return QString();
+ }
+}
+
+inline static bool toBool(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::Bool) {
+ return reg->getbool();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toBool();
+ } else {
+ if (ok) *ok = false;
+ return false;
+ }
+}
+
+inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ QUrl base;
+ if (type == qMetaTypeId<QVariant>()) {
+ QVariant *var = reg->getvariantptr();
+ int vt = var->type();
+ if (vt == QVariant::Url) {
+ base = var->toUrl();
+ } else if (vt == QVariant::ByteArray) {
+ base = QUrl(QString::fromUtf8(var->toByteArray()));
+ } else if (vt == QVariant::String) {
+ base = QUrl(var->toString());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+ } else if (type == QMetaType::QString) {
+ base = QUrl(*reg->getstringptr());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+
+ if (!base.isEmpty() && base.isRelative())
+ return context->url.resolved(base);
+ else
+ return base;
+}
+
+static QObject *variantToQObject(const QVariant &value, bool *ok)
+{
+ if (ok) *ok = true;
+
+ if (value.userType() == QMetaType::QObjectStar) {
+ return qvariant_cast<QObject*>(value);
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::init()
+{
+ if (program->subscriptions)
+ subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions];
+ if (program->identifiers)
+ identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
+
+ bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings];
+}
+
+static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
+{
+ QVariant qtscript = qtscriptRaw;
+
+ if (qtscript.userType() == v4.userType()) {
+ } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
+ qtscript.convert((QVariant::Type)v4.userType());
+ } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
+ qtscript = qVariantFromValue<QObject *>(0);
+ } else {
+ return false;
+ }
+
+ int type = qtscript.userType();
+
+ if (type == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ QDeclarativeAnchorLine la = qvariant_cast<QDeclarativeAnchorLine>(qtscript);
+ QDeclarativeAnchorLine ra = qvariant_cast<QDeclarativeAnchorLine>(v4);
+
+ return la == ra;
+ } else if (type == qMetaTypeId<QSGAnchorLine>()) {
+ QSGAnchorLine la = qvariant_cast<QSGAnchorLine>(qtscript);
+ QSGAnchorLine ra = qvariant_cast<QSGAnchorLine>(v4);
+
+ return la == ra;
+ } else if (type == QMetaType::Double) {
+
+ double la = qvariant_cast<double>(qtscript);
+ double lr = qvariant_cast<double>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else if (type == QMetaType::Float) {
+
+ float la = qvariant_cast<float>(qtscript);
+ float lr = qvariant_cast<float>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else {
+ return qtscript == v4;
+ }
+}
+
+QByteArray testResultToString(const QVariant &result, bool undefined)
+{
+ if (undefined) {
+ return "undefined";
+ } else {
+ QString rv;
+ QDebug d(&rv);
+ d << result;
+ return rv.toUtf8();
+ }
+}
+
+static void testBindingResult(const QString &binding, int line, int column,
+ QDeclarativeContextData *context, QObject *scope,
+ const Register &result, int resultType)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ bool iserror = false;
+ QByteArray qtscriptResult;
+ QByteArray v4Result;
+
+ if (expression.hasError()) {
+ iserror = true;
+ qtscriptResult = "exception";
+ } else {
+ qtscriptResult = testResultToString(value, isUndefined);
+ }
+
+ if (isUndefined && result.isUndefined()) {
+ return;
+ } else if(isUndefined != result.isUndefined()) {
+ iserror = true;
+ }
+
+ QVariant v4value;
+ if (!result.isUndefined()) {
+ switch (resultType) {
+ case QMetaType::QString:
+ v4value = *result.getstringptr();
+ break;
+ case QMetaType::QUrl:
+ v4value = *result.geturlptr();
+ break;
+ case QMetaType::QObjectStar:
+ v4value = qVariantFromValue<QObject *>(result.getQObject());
+ break;
+ case QMetaType::Bool:
+ v4value = result.getbool();
+ break;
+ case QMetaType::Int:
+ v4value = result.getint();
+ break;
+ case QMetaType::QReal:
+ v4value = result.getqreal();
+ break;
+ default:
+ if (resultType == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ v4value = qVariantFromValue<QDeclarativeAnchorLine>(*(QDeclarativeAnchorLine *)result.typeDataPtr());
+ } else if (resultType == qMetaTypeId<QSGAnchorLine>()) {
+ v4value = qVariantFromValue<QSGAnchorLine>(*(QSGAnchorLine *)result.typeDataPtr());
+ } else {
+ iserror = true;
+ v4Result = "Unknown V4 type";
+ }
+ }
+ }
+ if (v4Result.isEmpty())
+ v4Result = testResultToString(v4value, result.isUndefined());
+
+ if (!testCompareVariants(value, v4value))
+ iserror = true;
+
+ if (iserror) {
+ qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: " << v4Result.constData();
+ }
+}
+
+static void testBindingException(const QString &binding, int line, int column,
+ QDeclarativeContextData *context, QObject *scope)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ if (!expression.hasError()) {
+ QByteArray qtscriptResult = testResultToString(value, isUndefined);
+ qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: exception";
+ }
+}
+
+static void throwException(int id, QDeclarativeDelayedError *error,
+ QDeclarativeV4Program *program, QDeclarativeContextData *context,
+ const QString &description = QString())
+{
+ error->error.setUrl(context->url);
+ if (description.isEmpty())
+ error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
+ else
+ error->error.setDescription(description);
+ if (id != 0xFF) {
+ quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
+ error->error.setLine((e >> 32) & 0xFFFFFFFF);
+ error->error.setColumn(e & 0xFFFFFFFF);
+ } else {
+ error->error.setLine(-1);
+ error->error.setColumn(-1);
+ }
+ if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
+ QDeclarativeEnginePrivate::warning(context->engine, error->error);
+}
+
+const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
+
+qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+ const double D31 = D32 / 2.0;
+
+ if (sign == -1 && n < -D31)
+ n += D32;
+
+ else if (sign != -1 && n >= D31)
+ n -= D32;
+
+ return qint32 (n);
+}
+
+inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+
+ if (n < 0)
+ n += D32;
+
+ return quint32 (n);
+}
+
+#define THROW_EXCEPTION_STR(id, str) { \
+ if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
+ throwException((id), error, program, context, (str)); \
+ goto exceptionExit; \
+}
+
+#define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
+
+#define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
+#define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
+
+#define STRING_REGISTER(reg) { \
+ registers[(reg)].settype(QStringType); \
+ MARK_REGISTER(reg); \
+}
+
+#define URL_REGISTER(reg) { \
+ registers[(reg)].settype(QUrlType); \
+ MARK_REGISTER(reg); \
+}
+
+#define VARIANT_REGISTER(reg) { \
+ registers[(reg)].settype(QVariantType); \
+ MARK_REGISTER(reg); \
+}
+
+#ifdef QML_THREADED_INTERPRETER
+void **QDeclarativeV4Bindings::getDecodeInstrTable()
+{
+ static void **decode_instr;
+ if (!decode_instr) {
+ QDeclarativeV4Bindings dummy(0, 0);
+ quint32 executedBlocks = 0;
+ dummy.d_func()->run(0, executedBlocks, 0, 0, 0, 0, QDeclarativePropertyPrivate::BypassInterceptor, &decode_instr);
+ }
+ return decode_instr;
+}
+#endif
+
+void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
+ QDeclarativeContextData *context, QDeclarativeDelayedError *error,
+ QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ ,void ***table
+#endif
+ )
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+#ifdef QML_THREADED_INTERPRETER
+ if (table) {
+ static void *decode_instr[] = {
+ FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
+ };
+
+ *table = decode_instr;
+ return;
+ }
+#endif
+
+
+ error->removeError();
+
+ Register registers[32];
+ quint32 cleanupRegisterMask = 0;
+
+ executedBlocks = 0;
+
+ QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
+ const char *code = program->instructions();
+ code += instrIndex * QML_INSTR_SIZE(Jump, jump);
+ const Instr *instr = (const Instr *) code;
+
+ const char *data = program->data();
+
+ QString *testBindingSource = 0;
+ bool testBinding = false;
+ int bindingLine = 0;
+ int bindingColumn = 0;
+
+#ifdef QML_THREADED_INTERPRETER
+ goto *instr->common.code;
+#else
+ for (;;) {
+ switch (instr->common.type) {
+#endif
+
+ QML_BEGIN_INSTR(Noop, common)
+ QML_END_INSTR(Noop, common)
+
+ QML_BEGIN_INSTR(BindingId, id)
+ bindingLine = instr->id.line;
+ bindingColumn = instr->id.column;
+ QML_END_INSTR(BindingId, id)
+
+ QML_BEGIN_INSTR(SubscribeId, subscribeop)
+ subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
+ QML_END_INSTR(SubscribeId, subscribeop)
+
+ QML_BEGIN_INSTR(Subscribe, subscribeop)
+ {
+ QObject *o = 0;
+ const Register &object = registers[instr->subscribeop.reg];
+ if (!object.isUndefined()) o = object.getQObject();
+ subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
+ }
+ QML_END_INSTR(Subscribe, subscribeop)
+
+ QML_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+ {
+ Register &reg = registers[instr->fetchAndSubscribe.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ reg.setUndefined();
+ } else {
+ int subIdx = instr->fetchAndSubscribe.subscription;
+ QDeclarativeV4BindingsPrivate::Subscription *sub = 0;
+ if (subIdx != -1) {
+ sub = (subscriptions + subIdx);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIdx;
+ }
+ reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
+ if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetchAndSubscribe.reg);
+ QDeclarativeV4Compiler::fastPropertyAccessor()->accessor(instr->fetchAndSubscribe.function)(object, reg.typeDataPtr(), sub);
+ }
+ }
+ QML_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+
+ QML_BEGIN_INSTR(LoadId, load)
+ registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
+ QML_END_INSTR(LoadId, load)
+
+ QML_BEGIN_INSTR(LoadScope, load)
+ registers[instr->load.reg].setQObject(scope);
+ QML_END_INSTR(LoadScope, load)
+
+ QML_BEGIN_INSTR(LoadRoot, load)
+ registers[instr->load.reg].setQObject(context->contextObject);
+ QML_END_INSTR(LoadRoot, load)
+
+ QML_BEGIN_INSTR(LoadAttached, attached)
+ {
+ const Register &input = registers[instr->attached.reg];
+ Register &output = registers[instr->attached.output];
+ if (input.isUndefined())
+ THROW_EXCEPTION(instr->attached.exceptionId);
+
+ QObject *object = registers[instr->attached.reg].getQObject();
+ if (!object) {
+ output.setUndefined();
+ } else {
+ QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
+ Q_ASSERT(attached);
+ output.setQObject(attached);
+ }
+ }
+ QML_END_INSTR(LoadAttached, attached)
+
+ QML_BEGIN_INSTR(UnaryNot, unaryop)
+ {
+ registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
+ }
+ QML_END_INSTR(UnaryNot, unaryop)
+
+ QML_BEGIN_INSTR(UnaryMinusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
+ }
+ QML_END_INSTR(UnaryMinusReal, unaryop)
+
+ QML_BEGIN_INSTR(UnaryMinusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
+ }
+ QML_END_INSTR(UnaryMinusInt, unaryop)
+
+ QML_BEGIN_INSTR(UnaryPlusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
+ }
+ QML_END_INSTR(UnaryPlusReal, unaryop)
+
+ QML_BEGIN_INSTR(UnaryPlusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
+ }
+ QML_END_INSTR(UnaryPlusInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(src.getbool());
+ }
+ QML_END_INSTR(ConvertBoolToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(src.getbool());
+ }
+ QML_END_INSTR(ConvertBoolToReal, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertBoolToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getint());
+ }
+ QML_END_INSTR(ConvertIntToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qreal(src.getint()));
+ }
+ QML_END_INSTR(ConvertIntToReal, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getint()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertIntToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getqreal() != 0);
+ }
+ QML_END_INSTR(ConvertRealToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(toInt32(src.getqreal()));
+ }
+ QML_END_INSTR(ConvertRealToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getqreal()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertRealToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(tmp.toBool());
+ }
+ }
+ QML_END_INSTR(ConvertStringToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setint(tmp.toInt32());
+ }
+ }
+ QML_END_INSTR(ConvertStringToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setqreal(tmp.toNumber());
+ }
+ }
+ QML_END_INSTR(ConvertStringToReal, unaryop)
+
+ QML_BEGIN_INSTR(MathSinReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qSin(src.getqreal()));
+ }
+ QML_END_INSTR(MathSinReal, unaryop)
+
+ QML_BEGIN_INSTR(MathCosReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qCos(src.getqreal()));
+ }
+ QML_END_INSTR(MathCosReal, unaryop)
+
+ QML_BEGIN_INSTR(MathRoundReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qRound(src.getqreal()));
+ }
+ QML_END_INSTR(MathRoundReal, unaryop)
+
+ QML_BEGIN_INSTR(MathFloorReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qFloor(src.getqreal()));
+ }
+ QML_END_INSTR(MathFloorReal, unaryop)
+
+ QML_BEGIN_INSTR(MathPIReal, unaryop)
+ {
+ static const qsreal qmlPI = 2.0 * qAsin(1.0);
+ Register &output = registers[instr->unaryop.output];
+ output.setqreal(qmlPI);
+ }
+ QML_END_INSTR(MathPIReal, unaryop)
+
+ QML_BEGIN_INSTR(Real, real_value)
+ registers[instr->real_value.reg].setqreal(instr->real_value.value);
+ QML_END_INSTR(Real, real_value)
+
+ QML_BEGIN_INSTR(Int, int_value)
+ registers[instr->int_value.reg].setint(instr->int_value.value);
+ QML_END_INSTR(Int, int_value)
+
+ QML_BEGIN_INSTR(Bool, bool_value)
+ registers[instr->bool_value.reg].setbool(instr->bool_value.value);
+ QML_END_INSTR(Bool, bool_value)
+
+ QML_BEGIN_INSTR(String, string_value)
+ {
+ Register &output = registers[instr->string_value.reg];
+ QChar *string = (QChar *)(data + instr->string_value.offset);
+ new (output.getstringptr()) QString(string, instr->string_value.length);
+ STRING_REGISTER(instr->string_value.reg);
+ }
+ QML_END_INSTR(String, string_value)
+
+ QML_BEGIN_INSTR(EnableV4Test, string_value)
+ {
+ testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
+ testBinding = true;
+ }
+ QML_END_INSTR(String, string_value)
+
+ QML_BEGIN_INSTR(BitAndInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitAndInt, binaryop)
+
+ QML_BEGIN_INSTR(BitOrInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitAndInt, binaryop)
+
+ QML_BEGIN_INSTR(BitXorInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitXorInt, binaryop)
+
+ QML_BEGIN_INSTR(AddReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() +
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(AddReal, binaryop)
+
+ QML_BEGIN_INSTR(AddString, binaryop)
+ {
+ QString &string = *registers[instr->binaryop.output].getstringptr();
+ if (instr->binaryop.output == instr->binaryop.left) {
+ string += registers[instr->binaryop.right].getstringptr();
+ } else {
+ string = *registers[instr->binaryop.left].getstringptr() +
+ *registers[instr->binaryop.right].getstringptr();
+ }
+ }
+ QML_END_INSTR(AddString, binaryop)
+
+ QML_BEGIN_INSTR(SubReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() -
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(SubReal, binaryop)
+
+ QML_BEGIN_INSTR(MulReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() *
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(MulReal, binaryop)
+
+ QML_BEGIN_INSTR(DivReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() /
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(DivReal, binaryop)
+
+ QML_BEGIN_INSTR(ModReal, binaryop)
+ {
+ Register &target = registers[instr->binaryop.output];
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ if (QMetaType::QReal == QMetaType::Float)
+ target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
+ else
+ target.setqreal(::fmod(left.getqreal(), right.getqreal()));
+ }
+ QML_END_INSTR(ModInt, binaryop)
+
+ QML_BEGIN_INSTR(LShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(LShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(RShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(RShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(URShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(URShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(GtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(GtReal, binaryop)
+
+ QML_BEGIN_INSTR(LtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(LtReal, binaryop)
+
+ QML_BEGIN_INSTR(GeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(GeReal, binaryop)
+
+ QML_BEGIN_INSTR(LeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(LeReal, binaryop)
+
+ QML_BEGIN_INSTR(EqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(EqualReal, binaryop)
+
+ QML_BEGIN_INSTR(NotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(NotEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(StrictEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(StrictEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(StrictNotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(StrictNotEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(GtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a > b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(GtString, binaryop)
+
+ QML_BEGIN_INSTR(LtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a < b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(LtString, binaryop)
+
+ QML_BEGIN_INSTR(GeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a >= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(GeString, binaryop)
+
+ QML_BEGIN_INSTR(LeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a <= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(LeString, binaryop)
+
+ QML_BEGIN_INSTR(EqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(EqualString, binaryop)
+
+ QML_BEGIN_INSTR(NotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(NotEqualString, binaryop)
+
+ QML_BEGIN_INSTR(StrictEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(StrictEqualString, binaryop)
+
+ QML_BEGIN_INSTR(StrictNotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(StrictNotEqualString, binaryop)
+
+ QML_BEGIN_INSTR(NewString, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.getstringptr()) QString;
+ STRING_REGISTER(instr->construct.reg);
+ }
+ QML_END_INSTR(NewString, construct)
+
+ QML_BEGIN_INSTR(NewUrl, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.geturlptr()) QUrl;
+ URL_REGISTER(instr->construct.reg);
+ }
+ QML_END_INSTR(NewUrl, construct)
+
+ QML_BEGIN_INSTR(Fetch, fetch)
+ {
+ Register &reg = registers[instr->fetch.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+ } else {
+ reg.init((Register::Type)instr->fetch.valueType);
+ if (instr->fetch.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetch.reg);
+ void *argv[] = { reg.typeDataPtr(), 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
+ }
+ }
+ QML_END_INSTR(Fetch, fetch)
+
+ QML_BEGIN_INSTR(TestV4Store, storetest)
+ {
+ Register &data = registers[instr->storetest.reg];
+ testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
+ scope, data, instr->storetest.regType);
+ }
+ QML_END_INSTR(TestV4Store, storetest)
+
+ QML_BEGIN_INSTR(Store, store)
+ {
+ Register &data = registers[instr->store.reg];
+
+ if (data.isUndefined())
+ THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
+
+ int status = -1;
+ void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
+ QMetaObject::metacall(output, QMetaObject::WriteProperty,
+ instr->store.index, argv);
+
+ goto programExit;
+ }
+ QML_END_INSTR(Store, store)
+
+ QML_BEGIN_INSTR(Copy, copy)
+ registers[instr->copy.reg].copy(registers[instr->copy.src]);
+ if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
+ MARK_REGISTER(instr->copy.reg);
+ QML_END_INSTR(Copy, copy)
+
+ QML_BEGIN_INSTR(Jump, jump)
+ if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
+ code += instr->jump.count;
+ QML_END_INSTR(Jump, jump)
+
+ QML_BEGIN_INSTR(BranchTrue, branchop)
+ if (registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_END_INSTR(BranchTrue, branchop)
+
+ QML_BEGIN_INSTR(BranchFalse, branchop)
+ if (! registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_END_INSTR(BranchFalse, branchop)
+
+ QML_BEGIN_INSTR(Branch, branchop)
+ code += instr->branchop.offset;
+ QML_END_INSTR(Branch, branchop)
+
+ QML_BEGIN_INSTR(Block, blockop)
+ executedBlocks |= instr->blockop.block;
+ QML_END_INSTR(Block, blockop)
+
+ QML_BEGIN_INSTR(InitString, initstring)
+ if (!identifiers[instr->initstring.offset].identifier) {
+ quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
+ QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
+
+ QString str = QString::fromRawData(strdata, len);
+
+ identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+ }
+ QML_END_INSTR(InitString, initstring)
+
+ QML_BEGIN_INSTR(CleanupRegister, cleanup)
+ registers[instr->cleanup.reg].cleanup();
+ QML_END_INSTR(CleanupRegister, cleanup)
+
+#ifdef QML_THREADED_INTERPRETER
+ // nothing to do
+#else
+ default:
+ qFatal("QDeclarativeV4: Unknown instruction %d encountered.", instr->common.type);
+ break;
+ } // switch
+
+ } // while
+#endif
+
+ Q_ASSERT(!"Unreachable code reached");
+
+programExit:
+exceptionExit:
+ delete testBindingSource;
+
+ int reg = 0;
+ while (cleanupRegisterMask) {
+ if (cleanupRegisterMask & 0x1)
+ registers[reg].cleanup();
+
+ reg++;
+ cleanupRegisterMask >>= 1;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings_p.h b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
new file mode 100644
index 0000000000..9f225b65b6
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4BINDINGS_P_H
+#define QDECLARATIVEV4BINDINGS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4BindingsPrivate;
+class QDeclarativeV4Bindings : public QObject,
+ public QDeclarativeAbstractExpression,
+ public QDeclarativeRefCount
+{
+public:
+ QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context);
+ virtual ~QDeclarativeV4Bindings();
+
+ QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
+
+#ifdef QML_THREADED_INTERPRETER
+ static void **getDecodeInstrTable();
+#endif
+
+protected:
+ int qt_metacall(QMetaObject::Call, int, void **);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeV4Bindings)
+ Q_DECLARE_PRIVATE(QDeclarativeV4Bindings)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4BINDINGS_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler.cpp b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
new file mode 100644
index 0000000000..a7eecce0c9
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
@@ -0,0 +1,1340 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4compiler_p.h"
+#include "qdeclarativev4compiler_p_p.h"
+#include "qdeclarativev4program_p.h"
+#include "qdeclarativev4ir_p.h"
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativejsast_p.h>
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
+DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
+
+Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties)
+
+static bool qmlBindingsTest = false;
+
+using namespace QDeclarativeJS;
+QDeclarativeV4CompilerPrivate::QDeclarativeV4CompilerPrivate()
+: _function(0) , _block(0) , _discarded(false)
+{
+}
+
+//
+// tracing
+//
+void QDeclarativeV4CompilerPrivate::trace(int line, int column)
+{
+ bytecode.clear();
+
+ this->currentReg = _function->tempCount;
+
+ foreach (IR::BasicBlock *bb, _function->basicBlocks) {
+ if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
+ bb->JUMP(_function->basicBlocks.at(bb->index + 1));
+ }
+
+ QVector<IR::BasicBlock *> blocks;
+ trace(&blocks);
+ currentBlockMask = 0x00000001;
+
+
+ for (int i = 0; i < blocks.size(); ++i) {
+ IR::BasicBlock *block = blocks.at(i);
+ IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump()) {
+ if (cj->iffalse != next) {
+ block->i(new IR::Jump(cj->iffalse));
+ }
+ } else if (IR::Jump *j = terminator->asJump()) {
+ if (j->target == next) {
+ delete block->statements.back();
+ block->statements.resize(block->statements.size() - 1);
+ }
+ }
+ }
+
+ block->offset = bytecode.size();
+
+ if (bytecode.isEmpty()) {
+ if (qmlBindingsTest || bindingsDump()) {
+ Instr id;
+ id.common.type = Instr::BindingId;
+ id.id.column = column;
+ id.id.line = line;
+ gen(id);
+ }
+
+ if (qmlBindingsTest) {
+ QString str = expression->expression.asScript();
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr test;
+ test.common.type = Instr::EnableV4Test;
+ test.string_value.reg = 0;
+ test.string_value.offset = offset;
+ test.string_value.length = str.length();
+ gen(test);
+ }
+ }
+
+ bool usic = false;
+ int patchesCount = patches.count();
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ int blockopIndex = bytecode.size();
+ Instr blockop;
+ blockop.block(currentBlockMask);
+ gen(blockop);
+
+ foreach (IR::Stmt *s, block->statements)
+ s->accept(this);
+
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ if (usic) {
+ if (currentBlockMask == 0x80000000) {
+ discard();
+ return;
+ }
+ currentBlockMask <<= 1;
+ } else {
+ const int adjust = bytecode.remove(blockopIndex);
+ // Correct patches
+ for (int ii = patchesCount; ii < patches.count(); ++ii)
+ patches[ii].offset -= adjust;
+ }
+ }
+
+#ifdef DEBUG_IR_STRUCTURE
+ IR::IRDump dump;
+ for (int i = 0; i < blocks.size(); ++i) {
+ dump.basicblock(blocks.at(i));
+ }
+#endif
+
+
+ // back patching
+ foreach (const Patch &patch, patches) {
+ Instr &instr = bytecode[patch.offset];
+ instr.branchop.offset = patch.block->offset - patch.offset - instr.size();
+ }
+
+ patches.clear();
+}
+
+void QDeclarativeV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
+{
+ QList<IR::BasicBlock *> todo = QList<IR::BasicBlock *>::fromVector(_function->basicBlocks);
+ while (! todo.isEmpty()) {
+ IR::BasicBlock *block = todo.takeFirst();
+
+ while (! blocks->contains(block)) {
+ blocks->append(block);
+
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump())
+ block = cj->iffalse;
+ else if (IR::Jump *j = terminator->asJump())
+ block = j->target;
+ }
+ }
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
+{
+ if (!e) {
+ discard();
+ } else {
+ qSwap(currentReg, r);
+ e->accept(this);
+ qSwap(currentReg, r);
+ }
+}
+
+//
+// expressions
+//
+void QDeclarativeV4CompilerPrivate::visitConst(IR::Const *e)
+{
+ Instr i;
+ switch (e->type) {
+ case IR::BoolType:
+ i.move_reg_bool(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::IntType:
+ i.move_reg_int(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::RealType:
+ i.move_reg_qreal(currentReg, e->value);
+ gen(i);
+ break;
+
+ default:
+ if (qmlVerboseCompiler())
+ qWarning() << Q_FUNC_INFO << "unexpected type";
+ discard();
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitString(IR::String *e)
+{
+ registerLiteralString(currentReg, e->value);
+}
+
+void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
+{
+ if (e->base) {
+ // fetch the object and store it in reg.
+ traceExpression(e->base, currentReg);
+ } else {
+ _subscribeName.clear();
+ }
+
+ if (e->storage == IR::Name::RootStorage) {
+
+ Instr instr;
+ instr.load_root(currentReg);
+ gen(instr);
+
+ if (e->symbol == IR::Name::IdObject) {
+ // The ID is a reference to the root object
+ return;
+ }
+
+ } else if (e->storage == IR::Name::ScopeStorage) {
+
+ Instr instr;
+ instr.load_scope(currentReg);
+ gen(instr);
+
+ _subscribeName << contextName();
+
+ } else if (e->storage == IR::Name::IdStorage) {
+
+ Instr instr;
+ instr.load_id(currentReg, e->index);
+ gen(instr);
+
+ _subscribeName << QLatin1String("$$$ID_") + e->id;
+
+ if (blockNeedsSubscription(_subscribeName)) {
+ Instr sub;
+ sub.subscribeId(currentReg, subscriptionIndex(_subscribeName), instr.load.index);
+ gen(sub);
+ }
+
+ return;
+ } else {
+ // No action needed
+ }
+
+ switch (e->symbol) {
+ case IR::Name::Unbound:
+ case IR::Name::IdObject:
+ case IR::Name::Slot:
+ case IR::Name::Object: {
+ Q_ASSERT(!"Unreachable");
+ discard();
+ } break;
+
+ case IR::Name::AttachType: {
+ _subscribeName << e->id;
+
+ Instr attached;
+ attached.common.type = Instr::LoadAttached;
+ attached.attached.output = currentReg;
+ attached.attached.reg = currentReg;
+ attached.attached.exceptionId = exceptionId(e->line, e->column);
+ Q_ASSERT(e->declarativeType->attachedPropertiesId() != -1);
+ attached.attached.id = e->declarativeType->attachedPropertiesId();
+ gen(attached);
+ } break;
+
+ case IR::Name::Property: {
+ _subscribeName << e->id;
+
+ QMetaProperty prop = e->meta->property(e->index);
+ int fastFetchIndex = fastProperties()->accessorIndexForProperty(e->meta, e->index);
+
+ const int propTy = prop.userType();
+ QDeclarativeRegisterType regType;
+
+ switch (propTy) {
+ case QMetaType::QReal:
+ regType = QRealType;
+ break;
+ case QMetaType::Bool:
+ regType = BoolType;
+ break;
+ case QMetaType::Int:
+ regType = IntType;
+ break;
+ case QMetaType::QString:
+ regType = QStringType;
+ break;
+
+ default:
+ if (propTy == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ regType = PODValueType;
+ } else if (propTy == qMetaTypeId<QSGAnchorLine>()) {
+ regType = PODValueType;
+ } else if (QDeclarativeMetaType::isQObject(propTy)) {
+ regType = QObjectStarType;
+ } else {
+ if (qmlVerboseCompiler())
+ qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
+ discard(); // Unsupported type
+ return;
+ }
+
+ break;
+ } // switch
+
+ Instr fetch;
+
+ if (fastFetchIndex != -1) {
+ fetch.common.type = Instr::FetchAndSubscribe;
+ fetch.fetchAndSubscribe.reg = currentReg;
+ fetch.fetchAndSubscribe.function = fastFetchIndex;
+ fetch.fetchAndSubscribe.subscription = subscriptionIndex(_subscribeName);
+ fetch.fetchAndSubscribe.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetchAndSubscribe.valueType = regType;
+ } else {
+ if (blockNeedsSubscription(_subscribeName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
+ Instr sub;
+ sub.subscribe(currentReg, subscriptionIndex(_subscribeName), prop.notifySignalIndex());
+ gen(sub);
+ }
+
+ fetch.common.type = Instr::Fetch;
+ fetch.fetch.reg = currentReg;
+ fetch.fetch.index = e->index;
+ fetch.fetch.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetch.valueType = regType;
+ }
+
+ gen(fetch);
+
+ } break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::visitTemp(IR::Temp *e)
+{
+ if (currentReg != e->index) {
+ Instr i;
+ i.move_reg_reg(currentReg, e->index);
+ gen(i);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
+{
+ Instr i;
+
+ quint8 src = currentReg;
+
+ if (IR::Temp *temp = e->expr->asTemp()) {
+ src = temp->index;
+ } else {
+ traceExpression(e->expr, src);
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ Q_ASSERT(!"unreachable");
+ break;
+
+ case IR::OpIfTrue:
+ if (src != currentReg) {
+ i.move_reg_reg(currentReg, src);
+ gen(i);
+ } else {
+ // nothing to do
+ }
+ break;
+
+ case IR::OpNot:
+ i.unary_not(currentReg, src);
+ gen(i);
+ break;
+
+ case IR::OpUMinus:
+ if (e->expr->type == IR::RealType) {
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpUPlus:
+ if (e->expr->type == IR::RealType) {
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpCompl:
+ i.ucompl_real(currentReg, src);
+ gen(i);
+ discard(); // ???
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpAdd:
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ case IR::OpAnd:
+ case IR::OpOr:
+ Q_ASSERT(!"unreachable");
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::RealType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToReal;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToReal;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ // nothing to do
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::IntType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToInt;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ // nothing to do
+ return;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToInt;
+ gen(conv);
+ break;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::BoolType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ // nothing to do
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToBool;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToBool;
+ gen(conv);
+ return;
+
+ case IR::StringType:
+ conv.common.type = Instr::ConvertStringToBool;
+ gen(conv);
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+quint8 QDeclarativeV4CompilerPrivate::instructionOpcode(IR::Binop *e)
+{
+ switch (e->op) {
+ case IR::OpInvalid:
+ return Instr::Noop;
+
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ return Instr::Noop;
+
+ case IR::OpBitAnd:
+ return Instr::BitAndInt;
+
+ case IR::OpBitOr:
+ return Instr::BitOrInt;
+
+ case IR::OpBitXor:
+ return Instr::BitXorInt;
+
+ case IR::OpAdd:
+ if (e->type == IR::StringType)
+ return Instr::AddString;
+ return Instr::AddReal;
+
+ case IR::OpSub:
+ return Instr::SubReal;
+
+ case IR::OpMul:
+ return Instr::MulReal;
+
+ case IR::OpDiv:
+ return Instr::DivReal;
+
+ case IR::OpMod:
+ return Instr::ModReal;
+
+ case IR::OpLShift:
+ return Instr::LShiftInt;
+
+ case IR::OpRShift:
+ return Instr::RShiftInt;
+
+ case IR::OpURShift:
+ return Instr::URShiftInt;
+
+ case IR::OpGt:
+ if (e->left->type == IR::StringType)
+ return Instr::GtString;
+ return Instr::GtReal;
+
+ case IR::OpLt:
+ if (e->left->type == IR::StringType)
+ return Instr::LtString;
+ return Instr::LtReal;
+
+ case IR::OpGe:
+ if (e->left->type == IR::StringType)
+ return Instr::GeString;
+ return Instr::GeReal;
+
+ case IR::OpLe:
+ if (e->left->type == IR::StringType)
+ return Instr::LeString;
+ return Instr::LeReal;
+
+ case IR::OpEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::EqualString;
+ return Instr::EqualReal;
+
+ case IR::OpNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::NotEqualString;
+ return Instr::NotEqualReal;
+
+ case IR::OpStrictEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictEqualString;
+ return Instr::StrictEqualReal;
+
+ case IR::OpStrictNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictNotEqualString;
+ return Instr::StrictNotEqualReal;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ return Instr::Noop;
+
+ } // switch
+
+ return Instr::Noop;
+}
+
+void QDeclarativeV4CompilerPrivate::visitBinop(IR::Binop *e)
+{
+ int left = currentReg;
+ int right = currentReg + 1;
+
+ if (e->left->asTemp() && e->type != IR::StringType) // Not sure if the e->type != String test is needed
+ left = e->left->asTemp()->index;
+ else
+ traceExpression(e->left, left);
+
+ if (IR::Temp *t = e->right->asTemp())
+ right = t->index;
+ else
+ traceExpression(e->right, right);
+
+ if (e->left->type != e->right->type) {
+ if (qmlVerboseCompiler())
+ qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
+ << "(`" << IR::binaryOperator(e->left->type)
+ << "' and `"
+ << IR::binaryOperator(e->right->type)
+ << "'";
+ discard();
+ return;
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ discard();
+ break;
+
+ // unary
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ discard();
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ convertToInt(e->left, left);
+ convertToInt(e->right, right);
+ break;
+
+ case IR::OpAdd:
+ if (e->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ break;
+
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ if (e->left->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ discard(); // ### unreachable
+ break;
+ } // switch
+
+ const quint8 opcode = instructionOpcode(e);
+ if (opcode != Instr::Noop) {
+ Instr instr;
+ instr.common.type = opcode;
+ instr.binaryop.output = currentReg;
+ instr.binaryop.left = left;
+ instr.binaryop.right = right;
+ gen(instr);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitCall(IR::Call *call)
+{
+ if (IR::Name *name = call->base->asName()) {
+ if (call->args.size() == 1 && call->args.at(0)->type == IR::RealType) {
+ traceExpression(call->args.at(0), currentReg);
+
+ Instr instr;
+ instr.common.type = Instr::Noop;
+
+ switch (name->builtin) {
+ case IR::NoBuiltinSymbol:
+ break;
+
+ case IR::MathSinBultinFunction:
+ instr.math_sin_real(currentReg);
+ break;
+
+ case IR::MathCosBultinFunction:
+ instr.math_cos_real(currentReg);
+ break;
+
+ case IR::MathRoundBultinFunction:
+ instr.math_round_real(currentReg);
+ break;
+
+ case IR::MathFloorBultinFunction:
+ instr.math_floor_real(currentReg);
+ break;
+
+ case IR::MathPIBuiltinConstant:
+ break;
+ } // switch
+
+ if (instr.common.type != Instr::Noop) {
+ gen(instr);
+ return;
+ }
+ }
+ }
+
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
+ discard();
+}
+
+
+//
+// statements
+//
+void QDeclarativeV4CompilerPrivate::visitExp(IR::Exp *s)
+{
+ traceExpression(s->expr, currentReg);
+}
+
+void QDeclarativeV4CompilerPrivate::visitMove(IR::Move *s)
+{
+ IR::Temp *target = s->target->asTemp();
+ Q_ASSERT(target != 0);
+
+ quint8 dest = target->index;
+
+ if (target->type != s->source->type) {
+ quint8 src = dest;
+
+ if (IR::Temp *t = s->source->asTemp())
+ src = t->index;
+ else
+ traceExpression(s->source, dest);
+
+ Instr conv;
+ conv.common.type = Instr::Noop;
+ if (target->type == IR::BoolType) {
+ switch (s->source->type) {
+ case IR::IntType: conv.common.type = Instr::ConvertIntToBool; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToBool; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToBool; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::IntType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToInt; break;
+ case IR::RealType: {
+ if (s->isMoveForReturn)
+ conv.common.type = Instr::MathRoundReal;
+ else
+ conv.common.type = Instr::ConvertRealToInt;
+ break;
+ }
+ case IR::StringType: conv.common.type = Instr::ConvertStringToInt; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::RealType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToReal; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToReal; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToReal; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::StringType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToString; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToString; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToString; break;
+ default: break;
+ } // switch
+ }
+ if (conv.common.type != Instr::Noop) {
+ conv.unaryop.output = dest;
+ conv.unaryop.src = src;
+ gen(conv);
+ } else {
+ discard();
+ }
+ } else {
+ traceExpression(s->source, dest);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitJump(IR::Jump *s)
+{
+ patches.append(Patch(s->target, bytecode.size()));
+
+ Instr i;
+ i.branch(0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::visitCJump(IR::CJump *s)
+{
+ traceExpression(s->cond, currentReg);
+
+ patches.append(Patch(s->iftrue, bytecode.size()));
+
+ Instr i;
+ i.branch_true(currentReg, 0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::visitRet(IR::Ret *s)
+{
+ Q_ASSERT(s->expr != 0);
+
+ int storeReg = currentReg;
+
+ if (IR::Temp *temp = s->expr->asTemp()) {
+ storeReg = temp->index;
+ } else {
+ traceExpression(s->expr, storeReg);
+ }
+
+ if (qmlBindingsTest) {
+ Instr test;
+ test.common.type = Instr::TestV4Store;
+ test.storetest.reg = storeReg;
+ switch (s->type) {
+ case IR::StringType:
+ test.storetest.regType = QMetaType::QString;
+ break;
+ case IR::UrlType:
+ test.storetest.regType = QMetaType::QUrl;
+ break;
+ case IR::AnchorLineType:
+ test.storetest.regType = qMetaTypeId<QDeclarativeAnchorLine>();
+ break;
+ case IR::SGAnchorLineType:
+ test.storetest.regType = qMetaTypeId<QSGAnchorLine>();
+ break;
+ case IR::ObjectType:
+ test.storetest.regType = QMetaType::QObjectStar;
+ break;
+ case IR::BoolType:
+ test.storetest.regType = QMetaType::Bool;
+ break;
+ case IR::IntType:
+ test.storetest.regType = QMetaType::Int;
+ break;
+ case IR::RealType:
+ test.storetest.regType = QMetaType::QReal;
+ break;
+ default:
+ discard();
+ return;
+ }
+ gen(test);
+ }
+
+ Instr store;
+ store.common.type = Instr::Store;
+ store.store.output = 0;
+ store.store.index = expression->property->index;
+ store.store.reg = storeReg;
+ store.store.exceptionId = exceptionId(s->line, s->column);
+ gen(store);
+}
+
+void QDeclarativeV4Compiler::dump(const QByteArray &programData)
+{
+ const QDeclarativeV4Program *program = (const QDeclarativeV4Program *)programData.constData();
+
+ qWarning() << "Program.bindings:" << program->bindings;
+ qWarning() << "Program.dataLength:" << program->dataLength;
+ qWarning() << "Program.subscriptions:" << program->subscriptions;
+ qWarning() << "Program.indentifiers:" << program->identifiers;
+
+ const int programSize = program->instructionCount;
+ const char *start = program->instructions();
+ const char *code = start;
+ const char *end = code + programSize;
+ while (code < end) {
+ Instr *instr = (Instr *) code;
+ instr->dump(code - start);
+ code += instr->size();
+ }
+}
+
+QDeclarativeFastProperties *QDeclarativeV4Compiler::fastPropertyAccessor()
+{
+ return fastProperties();
+}
+
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "committed binding" states.
+*/
+void QDeclarativeV4CompilerPrivate::resetInstanceState()
+{
+ registerCleanups.clear();
+ data = committed.data;
+ exceptions = committed.exceptions;
+ usedSubscriptionIds.clear();
+ subscriptionIds = committed.subscriptionIds;
+ registeredStrings = committed.registeredStrings;
+ bytecode.clear();
+ patches.clear();
+ currentReg = 0;
+}
+
+/*!
+Mark the last compile as successful, and add it to the "committed data"
+section.
+
+Returns the index for the committed binding.
+*/
+int QDeclarativeV4CompilerPrivate::commitCompile()
+{
+ int rv = committed.count();
+ committed.offsets << committed.bytecode.count();
+ committed.dependencies << usedSubscriptionIds;
+ committed.bytecode += bytecode.code();
+ committed.data = data;
+ committed.exceptions = exceptions;
+ committed.subscriptionIds = subscriptionIds;
+ committed.registeredStrings = registeredStrings;
+ return rv;
+}
+
+bool QDeclarativeV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
+{
+ resetInstanceState();
+
+ if (expression->property->type == -1)
+ return false;
+
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *astExpression = node->expressionCast()) {
+ location = astExpression->firstSourceLocation();
+ } else if (AST::Statement *astStatement = node->statementCast()) {
+ if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
+ location = block->lbraceToken;
+ else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
+ location = ifStmt->ifToken;
+ else
+ return false;
+ } else {
+ return false;
+ }
+
+ IR::Module module;
+ IR::Function *function = 0;
+
+ QDeclarativeV4IRBuilder irBuilder(expression, engine);
+ if (!(function = irBuilder(&module, node)))
+ return false;
+
+ bool discarded = false;
+ qSwap(_discarded, discarded);
+ qSwap(_function, function);
+ trace(location.startLine, location.startColumn);
+ qSwap(_function, function);
+ qSwap(_discarded, discarded);
+
+ if (qmlVerboseCompiler()) {
+ QTextStream qerr(stderr, QIODevice::WriteOnly);
+ if (discarded)
+ qerr << "======== TODO ====== " << endl;
+ else
+ qerr << "==================== " << endl;
+ qerr << "\tline: " << location.startLine
+ << "\tcolumn: " << location.startColumn
+ << endl;
+ foreach (IR::BasicBlock *bb, function->basicBlocks)
+ bb->dump(qerr);
+ qerr << endl;
+ }
+
+ if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF)
+ return false;
+
+ return true;
+}
+
+// Returns a reg
+int QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QString &str)
+{
+ // ### string cleanup
+
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr string;
+ string.common.type = Instr::String;
+ string.string_value.reg = reg;
+ string.string_value.offset = offset;
+ string.string_value.length = str.length();
+ gen(string);
+
+ return reg;
+}
+
+// Returns an identifier offset
+int QDeclarativeV4CompilerPrivate::registerString(const QString &string)
+{
+ Q_ASSERT(!string.isEmpty());
+
+ QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
+
+ if (iter == registeredStrings.end()) {
+ quint32 len = string.length();
+ QByteArray lendata((const char *)&len, sizeof(quint32));
+ QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
+ strdata.prepend(lendata);
+ int rv = data.count();
+ data += strdata;
+
+ iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
+ }
+
+ Instr reg;
+ reg.common.type = Instr::InitString;
+ reg.initstring.offset = iter->first;
+ reg.initstring.dataIdx = iter->second;
+ gen(reg);
+ return reg.initstring.offset;
+}
+
+/*!
+Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
+*/
+bool QDeclarativeV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ return true;
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ if (uiter == usedSubscriptionIds.end())
+ return true;
+ else
+ return !(*uiter & currentBlockMask);
+}
+
+int QDeclarativeV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ iter = subscriptionIds.insert(str, subscriptionIds.count());
+ if (!(usedSubscriptionIds[*iter] & currentBlockMask)) {
+ usedSubscriptionIds[*iter] |= currentBlockMask;
+ usedSubscriptionIdsChanged = true;
+ }
+ return *iter;
+}
+
+quint32 QDeclarativeV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ Q_ASSERT(iter != subscriptionIds.end());
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ Q_ASSERT(uiter != usedSubscriptionIds.end());
+
+ return *uiter;
+}
+
+quint8 QDeclarativeV4CompilerPrivate::exceptionId(quint32 line, quint32 column)
+{
+ quint8 rv = 0xFF;
+ if (exceptions.count() < 0xFF) {
+ rv = (quint8)exceptions.count();
+ quint64 e = line;
+ e <<= 32;
+ e |= column;
+ exceptions.append(e);
+ }
+ return rv;
+}
+
+quint8 QDeclarativeV4CompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
+{
+ quint8 rv = 0xFF;
+ if (n && exceptions.count() < 0xFF) {
+ QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
+ rv = exceptionId(l.startLine, l.startColumn);
+ }
+ return rv;
+}
+
+QDeclarativeV4Compiler::QDeclarativeV4Compiler()
+: d(new QDeclarativeV4CompilerPrivate)
+{
+ qmlBindingsTest |= qmlBindingsTestEnv();
+}
+
+QDeclarativeV4Compiler::~QDeclarativeV4Compiler()
+{
+ delete d; d = 0;
+}
+
+/*
+Returns true if any bindings were compiled.
+*/
+bool QDeclarativeV4Compiler::isValid() const
+{
+ return !d->committed.bytecode.isEmpty();
+}
+
+/*
+-1 on failure, otherwise the binding index to use.
+*/
+int QDeclarativeV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
+{
+ if (!expression.expression.asAST()) return false;
+
+ if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
+ return -1;
+
+ if (qmlDisableOptimizer())
+ return -1;
+
+ d->expression = &expression;
+ d->engine = engine;
+
+ if (d->compile(expression.expression.asAST())) {
+ return d->commitCompile();
+ } else {
+ return -1;
+ }
+}
+
+QByteArray QDeclarativeV4CompilerPrivate::buildSignalTable() const
+{
+ QHash<int, QList<QPair<int, quint32> > > table;
+
+ for (int ii = 0; ii < committed.count(); ++ii) {
+ const QHash<int, quint32> &deps = committed.dependencies.at(ii);
+ for (QHash<int, quint32>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
+ table[iter.key()].append(qMakePair(ii, iter.value()));
+ }
+
+ QVector<quint32> header;
+ QVector<quint32> data;
+ for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
+ header.append(committed.subscriptionIds.count() + data.count());
+ const QList<QPair<int, quint32> > &bindings = table[ii];
+ data.append(bindings.count());
+ for (int jj = 0; jj < bindings.count(); ++jj) {
+ data.append(bindings.at(jj).first);
+ data.append(bindings.at(jj).second);
+ }
+ }
+ header << data;
+
+ return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
+}
+
+QByteArray QDeclarativeV4CompilerPrivate::buildExceptionData() const
+{
+ QByteArray rv;
+ rv.resize(committed.exceptions.count() * sizeof(quint64));
+ ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
+ return rv;
+}
+
+/*
+Returns the compiled program.
+*/
+QByteArray QDeclarativeV4Compiler::program() const
+{
+ QByteArray programData;
+
+ if (isValid()) {
+ QDeclarativeV4Program prog;
+ prog.bindings = d->committed.count();
+
+ Bytecode bc;
+ Instr jump;
+ jump.common.type = Instr::Jump;
+ jump.jump.reg = -1;
+
+ for (int ii = 0; ii < d->committed.count(); ++ii) {
+ jump.jump.count = d->committed.count() - ii - 1;
+ jump.jump.count*= jump.size();
+ jump.jump.count+= d->committed.offsets.at(ii);
+ bc.append(jump);
+ }
+
+
+ QByteArray bytecode = bc.code();
+ bytecode += d->committed.bytecode;
+
+ QByteArray data = d->committed.data;
+ while (data.count() % 4) data.append('\0');
+ prog.signalTableOffset = data.count();
+ data += d->buildSignalTable();
+ while (data.count() % 4) data.append('\0');
+ prog.exceptionDataOffset = data.count();
+ data += d->buildExceptionData();
+
+ prog.dataLength = 4 * ((data.size() + 3) / 4);
+ prog.subscriptions = d->committed.subscriptionIds.count();
+ prog.identifiers = d->committed.registeredStrings.count();
+ prog.instructionCount = bytecode.count();
+ int size = sizeof(QDeclarativeV4Program) + bytecode.count();
+ size += prog.dataLength;
+
+ programData.resize(size);
+ memcpy(programData.data(), &prog, sizeof(QDeclarativeV4Program));
+ if (prog.dataLength)
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->data(), data.constData(),
+ data.size());
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->instructions(), bytecode.constData(),
+ bytecode.count());
+ }
+
+ if (bindingsDump()) {
+ qWarning().nospace() << "Subscription slots:";
+
+ for (QHash<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
+ iter != d->committed.subscriptionIds.end();
+ ++iter) {
+ qWarning().nospace() << " " << iter.value() << "\t-> " << iter.key();
+ }
+
+
+ QDeclarativeV4Compiler::dump(programData);
+ }
+
+ return programData;
+}
+
+void QDeclarativeV4Compiler::enableBindingsTest(bool e)
+{
+ if (e)
+ qmlBindingsTest = true;
+ else
+ qmlBindingsTest = qmlBindingsTestEnv();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiledbindings_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
index f3d8b4b804..c10691dc87 100644
--- a/src/declarative/qml/qdeclarativecompiledbindings_p.h
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
-#define QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+#ifndef QDECLARATIVEV4COMPILER_P_H
+#define QDECLARATIVEV4COMPILER_P_H
//
// W A R N I N G
@@ -60,12 +60,14 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-struct QDeclarativeBindingCompilerPrivate;
-class QDeclarativeBindingCompiler
+class QDeclarativeFastProperties;
+class QDeclarativeTypeNameCache;
+class QDeclarativeV4CompilerPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeV4Compiler
{
public:
- QDeclarativeBindingCompiler();
- ~QDeclarativeBindingCompiler();
+ QDeclarativeV4Compiler();
+ ~QDeclarativeV4Compiler();
// Returns true if bindings were compiled
bool isValid() const;
@@ -77,6 +79,7 @@ public:
QDeclarativeParser::Property *property;
QDeclarativeParser::Variant expression;
QHash<QString, QDeclarativeParser::Object *> ids;
+ QDeclarativeTypeNameCache *importCache;
QDeclarativeImports imports;
};
@@ -87,30 +90,15 @@ public:
QByteArray program() const;
static void dump(const QByteArray &);
+ static QDeclarativeFastProperties *fastPropertyAccessor();
+ static void enableBindingsTest(bool);
private:
- QDeclarativeBindingCompilerPrivate *d;
-};
-
-class QDeclarativeCompiledBindingsPrivate;
-class QDeclarativeCompiledBindings : public QObject, public QDeclarativeAbstractExpression, public QDeclarativeRefCount
-{
-public:
- QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context);
- virtual ~QDeclarativeCompiledBindings();
-
- QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
-
-protected:
- int qt_metacall(QMetaObject::Call, int, void **);
-
-private:
- Q_DISABLE_COPY(QDeclarativeCompiledBindings)
- Q_DECLARE_PRIVATE(QDeclarativeCompiledBindings)
+ QDeclarativeV4CompilerPrivate *d;
};
QT_END_NAMESPACE
QT_END_HEADER
-#endif // QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+#endif // QDECLARATIVEV4COMPILER_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
new file mode 100644
index 0000000000..1b2a998422
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4COMPILER_P_P_H
+#define QDECLARATIVEV4COMPILER_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4ir_p.h"
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4CompilerPrivate: protected QDeclarativeJS::IR::ExprVisitor,
+ protected QDeclarativeJS::IR::StmtVisitor
+{
+public:
+ QDeclarativeV4CompilerPrivate();
+
+ void resetInstanceState();
+ int commitCompile();
+
+ const QDeclarativeV4Compiler::Expression *expression;
+ QDeclarativeEnginePrivate *engine;
+
+ QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)expression->context, 16); }
+
+ bool compile(QDeclarativeJS::AST::Node *);
+
+ QHash<int, QPair<int, int> > registerCleanups;
+
+ int registerLiteralString(quint8 reg, const QString &);
+ int registerString(const QString &);
+ QHash<QString, QPair<int, int> > registeredStrings;
+ QByteArray data;
+
+ bool blockNeedsSubscription(const QStringList &);
+ int subscriptionIndex(const QStringList &);
+ quint32 subscriptionBlockMask(const QStringList &);
+
+ quint8 exceptionId(quint32 line, quint32 column);
+ quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
+ QVector<quint64> exceptions;
+
+ QHash<int, quint32> usedSubscriptionIds;
+
+ QHash<QString, int> subscriptionIds;
+ QDeclarativeJS::Bytecode bytecode;
+
+ // back patching
+ struct Patch {
+ QDeclarativeJS::IR::BasicBlock *block; // the basic block
+ int offset; // the index of the instruction to patch
+ Patch(QDeclarativeJS::IR::BasicBlock *block = 0, int index = -1)
+ : block(block), offset(index) {}
+ };
+ QVector<Patch> patches;
+
+ // Committed binding data
+ struct {
+ QList<int> offsets;
+ QList<QHash<int, quint32> > dependencies;
+
+ //QDeclarativeJS::Bytecode bytecode;
+ QByteArray bytecode;
+ QByteArray data;
+ QHash<QString, int> subscriptionIds;
+ QVector<quint64> exceptions;
+
+ QHash<QString, QPair<int, int> > registeredStrings;
+
+ int count() const { return offsets.count(); }
+ } committed;
+
+ QByteArray buildSignalTable() const;
+ QByteArray buildExceptionData() const;
+
+ void convertToReal(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToInt(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToBool(QDeclarativeJS::IR::Expr *expr, int reg);
+ quint8 instructionOpcode(QDeclarativeJS::IR::Binop *e);
+
+protected:
+
+ //
+ // tracing
+ //
+ void trace(int line, int column);
+ void trace(QVector<QDeclarativeJS::IR::BasicBlock *> *blocks);
+ void traceExpression(QDeclarativeJS::IR::Expr *e, quint8 r);
+
+ inline void gen(const QDeclarativeJS::Instr &i) { bytecode.append(i); }
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ QStringList _subscribeName;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ void discard() { _discarded = true; }
+ bool _discarded;
+ quint8 currentReg;
+
+ bool usedSubscriptionIdsChanged;
+ quint32 currentBlockMask;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4COMPILER_P_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction.cpp b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
new file mode 100644
index 0000000000..1f24f30c25
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4bindings_p.h"
+
+#include <QtCore/qdebug.h>
+#include <private/qdeclarativeglobal_p.h>
+
+// Define this to do a test dump of all the instructions at startup. This is
+// helpful to test that each instruction's Instr::dump() case uses the correct
+// number of tabs etc and otherwise looks correct.
+// #define DEBUG_INSTR_DUMP
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+namespace QDeclarativeJS {
+
+#ifdef DEBUG_INSTR_DUMP
+static struct DumpInstrAtStartup {
+ DumpInstrAtStartup() {
+#define DUMP_INSTR_AT_STARTUP(Type, FMT) { Instr i; i.common.type = Instr::Type; i.dump(0); }
+ FOR_EACH_QML_INSTR(DUMP_INSTR_AT_STARTUP);
+ }
+} dump_instr_at_startup;
+#endif
+
+int Instr::size() const
+{
+#define QML_RETURN_INSTR_SIZE(I, FMT) case I: return QML_INSTR_SIZE(I, FMT);
+ switch (common.type) {
+ FOR_EACH_QML_INSTR(QML_RETURN_INSTR_SIZE)
+ }
+#undef QML_RETURN_INSTR_SIZE
+ return 0;
+}
+
+void Instr::dump(int address) const
+{
+ QByteArray leading;
+ if (address != -1) {
+ leading = QByteArray::number(address);
+ leading.prepend(QByteArray(8 - leading.count(), ' '));
+ leading.append("\t");
+ }
+
+#define INSTR_DUMP qWarning().nospace() << leading.constData()
+
+ switch (common.type) {
+ case Instr::Noop:
+ INSTR_DUMP << "\t" << "Noop";
+ break;
+ case Instr::BindingId:
+ INSTR_DUMP << id.line << ":" << id.column << ":";
+ break;
+ case Instr::Subscribe:
+ INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << subscribeop.reg << ") Notify_Signal(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::SubscribeId:
+ INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::FetchAndSubscribe:
+ INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << fetchAndSubscribe.reg << ") Fast_Accessor(" << fetchAndSubscribe.function << ") -> Output_Reg(" << fetchAndSubscribe.reg << ") Subscription_Slot(" << fetchAndSubscribe.subscription << ")";
+ break;
+ case Instr::LoadId:
+ INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << load.index << ") -> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadScope:
+ INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadRoot:
+ INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadAttached:
+ INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << attached.reg << ") Attached_Index(" << attached.id << ") -> Output_Reg(" << attached.output << ")";
+ break;
+ case Instr::UnaryNot:
+ INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusReal:
+ INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusInt:
+ INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusReal:
+ INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusInt:
+ INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToInt:
+ INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToReal:
+ INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToString:
+ INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToBool:
+ INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToReal:
+ INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToString:
+ INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToBool:
+ INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToInt:
+ INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToString:
+ INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToBool:
+ INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToInt:
+ INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToReal:
+ INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathSinReal:
+ INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathCosReal:
+ INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathRoundReal:
+ INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathFloorReal:
+ INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathPIReal:
+ INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::Real:
+ INSTR_DUMP << "\t" << "Real" << "\t\t\t" << "Constant(" << real_value.value << ") -> Output_Reg(" << real_value.reg << ")";
+ break;
+ case Instr::Int:
+ INSTR_DUMP << "\t" << "Int" << "\t\t\t" << "Constant(" << int_value.value << ") -> Output_Reg(" << int_value.reg << ")";
+ break;
+ case Instr::Bool:
+ INSTR_DUMP << "\t" << "Bool" << "\t\t\t" << "Constant(" << bool_value.value << ") -> Output_Reg(" << bool_value.reg << ")";
+ break;
+ case Instr::String:
+ INSTR_DUMP << "\t" << "String" << "\t\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ") -> Output_Register(" << string_value.reg << ")";
+ break;
+ case Instr::EnableV4Test:
+ INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ")";
+ break;
+ case Instr::TestV4Store:
+ INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << storetest.reg << ") Reg_Type(" << storetest.regType << ")";
+ break;
+ case Instr::BitAndInt:
+ INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitOrInt:
+ INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitXorInt:
+ INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddReal:
+ INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddString:
+ INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::SubReal:
+ INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::MulReal:
+ INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::DivReal:
+ INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::ModReal:
+ INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LShiftInt:
+ INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::RShiftInt:
+ INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::URShiftInt:
+ INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtReal:
+ INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtReal:
+ INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeReal:
+ INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeReal:
+ INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualReal:
+ INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualReal:
+ INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualReal:
+ INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualReal:
+ INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtString:
+ INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtString:
+ INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeString:
+ INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeString:
+ INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualString:
+ INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualString:
+ INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualString:
+ INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualString:
+ INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NewString:
+ INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::NewUrl:
+ INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::CleanupRegister:
+ INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << cleanup.reg << ")";
+ break;
+ case Instr::Fetch:
+ INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << fetch.reg << ") Property_Index(" << fetch.index << ") -> Output_Reg(" << fetch.reg << ")";
+ break;
+ case Instr::Store:
+ INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << store.reg << ") -> Object_Reg(" << store.output << ") Property_Index(" << store.index << ")";
+ break;
+ case Instr::Copy:
+ INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << copy.src << ") -> Output_Reg(" << copy.reg << ")";
+ break;
+ case Instr::Jump:
+ if (jump.reg != -1) {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ") [if false == Input_Reg(" << jump.reg << ")]";
+ } else {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ")";
+ }
+ break;
+ case Instr::BranchFalse:
+ INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if false == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::BranchTrue:
+ INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if true == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::Branch:
+ INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + branchop.offset) << ")";
+ break;
+ case Instr::InitString:
+ INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << initstring.dataIdx << ") -> String_Slot(" << initstring.offset << ")";
+ break;
+ case Instr::Block:
+ INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(blockop.block, 16).constData() << ")";
+ break;
+ default:
+ INSTR_DUMP << "\t" << "Unknown";
+ break;
+ }
+}
+
+void Instr::noop()
+{
+ common.type = Noop;
+}
+
+void Instr::load_root(quint8 reg)
+{
+ common.type = LoadRoot;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_scope(quint8 reg)
+{
+ common.type = LoadScope;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_id(quint8 reg, quint32 idIndex)
+{
+ common.type = LoadId;
+ load.reg = reg;
+ load.index = idIndex;
+}
+
+void Instr::subscribe(qint8 reg, quint16 subscribeSlot, quint32 notifyIndex)
+{
+ common.type = Instr::Subscribe;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = notifyIndex;
+}
+
+void Instr::subscribeId(qint8 reg, quint16 subscribeSlot, quint32 idIndex)
+{
+ common.type = Instr::SubscribeId;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = idIndex;
+}
+
+void Instr::move_reg_bool(quint8 reg, bool value)
+{
+ common.type = Bool;
+ bool_value.reg = reg;
+ bool_value.value = value;
+}
+
+void Instr::move_reg_int(quint8 reg, int value)
+{
+ common.type = Int;
+ int_value.reg = reg;
+ int_value.value = value;
+}
+
+void Instr::move_reg_qreal(quint8 reg, qreal value)
+{
+ common.type = Real;
+ real_value.reg = reg;
+ real_value.value = value;
+}
+
+void Instr::move_reg_reg(quint8 reg, quint8 src)
+{
+ common.type = Copy;
+ copy.reg = reg;
+ copy.src = src;
+}
+
+void Instr::unary_not(quint8 dest, quint8 src)
+{
+ common.type = UnaryNot;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::ucompl_real(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::ucompl_int(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::math_sin_real(quint8 reg)
+{
+ common.type = MathSinReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_cos_real(quint8 reg)
+{
+ common.type = MathCosReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_round_real(quint8 reg)
+{
+ common.type = MathRoundReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_floor_real(quint8 reg)
+{
+ common.type = MathFloorReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_pi_real(quint8 reg)
+{
+ common.type = MathPIReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::branch_true(quint8 reg, qint16 offset)
+{
+ common.type = BranchTrue;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch_false(quint8 reg, qint16 offset)
+{
+ common.type = BranchFalse;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch(qint16 offset)
+{
+ common.type = Branch;
+ branchop.offset = offset;
+}
+
+void Instr::block(quint32 mask)
+{
+ common.type = Block;
+ blockop.block = mask;
+}
+
+Bytecode::Bytecode()
+{
+#ifdef QML_THREADED_INTERPRETER
+ decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
+#endif
+}
+
+void Bytecode::append(const Instr &instr)
+{
+ const char *it;
+#ifdef QML_THREADED_INTERPRETER
+ Instr i = instr;
+ i.common.code = decodeInstr[i.common.type];
+ it = (const char *) &i;
+#else
+ it = (const char *) &instr;
+#endif
+ d.append(it, instr.size());
+}
+
+void Bytecode::append(const QVector<Instr> &instrs)
+{
+ foreach (const Instr &i, instrs)
+ append(i);
+}
+
+int Bytecode::remove(int offset)
+{
+ const Instr *instr = (const Instr *) (d.begin() + offset);
+ const int instrSize = instr->size();
+ d.remove(offset, instrSize);
+ return instrSize;
+}
+
+const Instr &Bytecode::operator[](int offset) const
+{
+ return *((const Instr *) (d.begin() + offset));
+}
+
+Instr &Bytecode::operator[](int offset)
+{
+ return *((Instr *) (d.begin() + offset));
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction_p.h b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
new file mode 100644
index 0000000000..f6e0bc734a
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
@@ -0,0 +1,444 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4INSTRUCTION_P_H
+#define QDECLARATIVEV4INSTRUCTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#define FOR_EACH_QML_INSTR(F) \
+ F(Noop, common) \
+ F(BindingId, id) \
+ F(Subscribe, subscribeop) \
+ F(SubscribeId, subscribeop) \
+ F(FetchAndSubscribe, fetchAndSubscribe) \
+ F(LoadId, load) \
+ F(LoadScope, load) \
+ F(LoadRoot, load) \
+ F(LoadAttached, attached) \
+ F(UnaryNot, unaryop) \
+ F(UnaryMinusReal, unaryop) \
+ F(UnaryMinusInt, unaryop) \
+ F(UnaryPlusReal, unaryop) \
+ F(UnaryPlusInt, unaryop) \
+ F(ConvertBoolToInt, unaryop) \
+ F(ConvertBoolToReal, unaryop) \
+ F(ConvertBoolToString, unaryop) \
+ F(ConvertIntToBool, unaryop) \
+ F(ConvertIntToReal, unaryop) \
+ F(ConvertIntToString, unaryop) \
+ F(ConvertRealToBool, unaryop) \
+ F(ConvertRealToInt, unaryop) \
+ F(ConvertRealToString, unaryop) \
+ F(ConvertStringToBool, unaryop) \
+ F(ConvertStringToInt, unaryop) \
+ F(ConvertStringToReal, unaryop) \
+ F(MathSinReal, unaryop) \
+ F(MathCosReal, unaryop) \
+ F(MathRoundReal, unaryop) \
+ F(MathFloorReal, unaryop) \
+ F(MathPIReal, unaryop) \
+ F(Real, real_value) \
+ F(Int, int_value) \
+ F(Bool, bool_value) \
+ F(String, string_value) \
+ F(EnableV4Test, string_value) \
+ F(TestV4Store, storetest) \
+ F(BitAndInt, binaryop) \
+ F(BitOrInt, binaryop) \
+ F(BitXorInt, binaryop) \
+ F(AddReal, binaryop) \
+ F(AddString, binaryop) \
+ F(SubReal, binaryop) \
+ F(MulReal, binaryop) \
+ F(DivReal, binaryop) \
+ F(ModReal, binaryop) \
+ F(LShiftInt, binaryop) \
+ F(RShiftInt, binaryop) \
+ F(URShiftInt, binaryop) \
+ F(GtReal, binaryop) \
+ F(LtReal, binaryop) \
+ F(GeReal, binaryop) \
+ F(LeReal, binaryop) \
+ F(EqualReal, binaryop) \
+ F(NotEqualReal, binaryop) \
+ F(StrictEqualReal, binaryop) \
+ F(StrictNotEqualReal, binaryop) \
+ F(GtString, binaryop) \
+ F(LtString, binaryop) \
+ F(GeString, binaryop) \
+ F(LeString, binaryop) \
+ F(EqualString, binaryop) \
+ F(NotEqualString, binaryop) \
+ F(StrictEqualString, binaryop) \
+ F(StrictNotEqualString, binaryop) \
+ F(NewString, construct) \
+ F(NewUrl, construct) \
+ F(CleanupRegister, cleanup) \
+ F(Copy, copy) \
+ F(Fetch, fetch) \
+ F(Store, store) \
+ F(Jump, jump) \
+ F(BranchTrue, branchop) \
+ F(BranchFalse, branchop) \
+ F(Branch, branchop) \
+ F(Block, blockop) \
+ /* Speculative property resolution */ \
+ F(InitString, initstring)
+
+#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
+# define QML_THREADED_INTERPRETER
+#endif
+
+#ifdef Q_ALIGNOF
+# define QML_INSTR_ALIGN_MASK (Q_ALIGNOF(Instr) - 1)
+#else
+# define QML_INSTR_ALIGN_MASK (sizeof(void *) - 1)
+#endif
+
+#define QML_INSTR_ENUM(I, FMT) I,
+#define QML_INSTR_ADDR(I, FMT) &&op_##I,
+#define QML_INSTR_SIZE(I, FMT) ((sizeof(Instr::instr_##FMT) + QML_INSTR_ALIGN_MASK) & ~QML_INSTR_ALIGN_MASK)
+
+#ifdef QML_THREADED_INTERPRETER
+# define QML_BEGIN_INSTR(I,FMT) op_##I:
+# define QML_END_INSTR(I,FMT) code += QML_INSTR_SIZE(I, FMT); instr = (const Instr *) code; goto *instr->common.code;
+# define QML_INSTR_HEADER void *code;
+#else
+# define QML_BEGIN_INSTR(I,FMT) case Instr::I:
+# define QML_END_INSTR(I,FMT) code += QML_INSTR_SIZE(I, FMT); instr = (const Instr *) code; break;
+# define QML_INSTR_HEADER
+#endif
+
+namespace QDeclarativeJS {
+
+union Instr {
+ int size() const;
+ void dump(int = -1) const;
+ void noop();
+ void load_root(quint8 reg);
+ void load_scope(quint8 reg);
+ void load_id(quint8 reg, quint32 idIndex);
+ void subscribe(qint8 reg, quint16 offset, quint32 index);
+ void subscribeId(qint8 reg, quint16 offset, quint32 index);
+ void move_reg_bool(quint8 reg, bool value);
+ void move_reg_int(quint8 reg, int value);
+ void move_reg_qreal(quint8 reg, qreal value);
+ void move_reg_reg(quint8 reg, quint8 src);
+
+ void unary_not(quint8 dest, quint8 src);
+ void uminus_real(quint8 dest, quint8 src);
+ void uminus_int(quint8 dest, quint8 src);
+ void uplus_real(quint8 dest, quint8 src);
+ void uplus_int(quint8 dest, quint8 src);
+ void ucompl_real(quint8 dest, quint8 src);
+ void ucompl_int(quint8 dest, quint8 src);
+
+ void math_sin_real(quint8 reg);
+ void math_cos_real(quint8 reg);
+ void math_round_real(quint8 reg);
+ void math_floor_real(quint8 reg);
+ void math_pi_real(quint8 reg);
+ void branch_true(quint8 reg, qint16 offset);
+ void branch_false(quint8 reg, qint16 offset);
+ void branch(qint16 offset);
+ void block(quint32 mask);
+
+ enum {
+ FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
+ };
+
+ struct instr_common {
+ QML_INSTR_HEADER
+ quint8 type;
+ };
+
+ struct instr_id {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 column;
+ quint32 line;
+ };
+
+ struct instr_init {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 subscriptions;
+ quint16 identifiers;
+ };
+
+ struct instr_subscribeop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 offset;
+ quint32 index;
+ };
+
+ struct instr_load {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 index;
+ };
+
+ struct instr_attached {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 id;
+ };
+
+ struct instr_store {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 index;
+ };
+
+ struct instr_storetest {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint32 regType;
+ };
+
+ struct instr_fetchAndSubscribe {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint16 subscription;
+ quint16 function;
+ };
+
+ struct instr_fetch{
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint32 index;
+ };
+
+ struct instr_copy {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ };
+
+ struct instr_construct {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_real_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qreal value; // XXX Makes the instruction 12 bytes
+ };
+
+ struct instr_int_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ int value;
+ };
+
+ struct instr_bool_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ bool value;
+ };
+
+ struct instr_string_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 length;
+ quint32 offset;
+ };
+
+ struct instr_binaryop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 left;
+ qint8 right;
+ };
+
+ struct instr_unaryop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 src;
+ };
+
+ struct instr_jump {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 count;
+ };
+
+ struct instr_find {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ quint8 exceptionId;
+ quint16 name;
+ quint16 subscribeIndex;
+ };
+
+ struct instr_cleanup {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_initstring {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 offset;
+ quint32 dataIdx;
+ };
+
+ struct instr_branchop {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint8 reg;
+ qint16 offset;
+ };
+
+ struct instr_blockop {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint32 block;
+ };
+
+ instr_common common;
+ instr_id id;
+ instr_init init;
+ instr_subscribeop subscribeop;
+ instr_load load;
+ instr_attached attached;
+ instr_store store;
+ instr_storetest storetest;
+ instr_fetchAndSubscribe fetchAndSubscribe;
+ instr_fetch fetch;
+ instr_copy copy;
+ instr_construct construct;
+ instr_real_value real_value;
+ instr_int_value int_value;
+ instr_bool_value bool_value;
+ instr_string_value string_value;
+ instr_binaryop binaryop;
+ instr_unaryop unaryop;
+ instr_jump jump;
+ instr_find find;
+ instr_cleanup cleanup;
+ instr_initstring initstring;
+ instr_branchop branchop;
+ instr_blockop blockop;
+};
+
+class Bytecode
+{
+ Q_DISABLE_COPY(Bytecode)
+
+public:
+ Bytecode();
+
+ QByteArray code() const { return d; }
+ const char *constData() const { return d.constData(); }
+ int size() const { return d.size(); }
+ int count() const { return d.count(); }
+ void clear() { d.clear(); }
+ bool isEmpty() const { return d.isEmpty(); }
+ void append(const Instr &instr);
+ void append(const QVector<Instr> &instrs);
+ int remove(int index);
+
+ const Instr &operator[](int offset) const;
+ Instr &operator[](int offset);
+
+private:
+ QByteArray d;
+#ifdef QML_THREADED_INTERPRETER
+ void **decodeInstr;
+#endif
+};
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4INSTRUCTION_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4ir.cpp b/src/declarative/qml/v4/qdeclarativev4ir.cpp
new file mode 100644
index 0000000000..7876e6ccea
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir.cpp
@@ -0,0 +1,832 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4ir_p.h"
+
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+namespace IR {
+
+inline const char *typeName(Type t)
+{
+ switch (t) {
+ case InvalidType: return "invalid";
+ case UndefinedType: return "undefined";
+ case NullType: return "null";
+ case VoidType: return "void";
+ case StringType: return "string";
+ case UrlType: return "url";
+ case AnchorLineType: return "AnchorLine";
+ case SGAnchorLineType: return "SGAnchorLine";
+ case AttachType: return "AttachType";
+ case ObjectType: return "object";
+ case BoolType: return "bool";
+ case IntType: return "int";
+ case RealType: return "qreal";
+ case RealNaNType: return "NaN";
+ default: return "invalid";
+ }
+}
+
+IR::Type maxType(IR::Type left, IR::Type right)
+{
+ if (left == right)
+ return left;
+ else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
+ return qMax(left, right);
+ else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
+ (right >= IR::FirstNumberType && left == IR::StringType))
+ return IR::StringType;
+ else
+ return IR::InvalidType;
+}
+
+
+const char *opname(AluOp op)
+{
+ switch (op) {
+ case OpInvalid: return "?";
+
+ case OpIfTrue: return "(bool)";
+ case OpNot: return "!";
+ case OpUMinus: return "-";
+ case OpUPlus: return "+";
+ case OpCompl: return "~";
+
+ case OpBitAnd: return "&";
+ case OpBitOr: return "|";
+ case OpBitXor: return "^";
+
+ case OpAdd: return "+";
+ case OpSub: return "-";
+ case OpMul: return "*";
+ case OpDiv: return "/";
+ case OpMod: return "%";
+
+ case OpLShift: return "<<";
+ case OpRShift: return ">>";
+ case OpURShift: return ">>>";
+
+ case OpGt: return ">";
+ case OpLt: return "<";
+ case OpGe: return ">=";
+ case OpLe: return "<=";
+ case OpEqual: return "==";
+ case OpNotEqual: return "!=";
+ case OpStrictEqual: return "===";
+ case OpStrictNotEqual: return "!==";
+
+ case OpAnd: return "&&";
+ case OpOr: return "||";
+
+ default: return "?";
+
+ } // switch
+}
+
+AluOp binaryOperator(int op)
+{
+ switch (static_cast<QSOperator::Op>(op)) {
+ case QSOperator::Add: return OpAdd;
+ case QSOperator::And: return OpAnd;
+ case QSOperator::BitAnd: return OpBitAnd;
+ case QSOperator::BitOr: return OpBitOr;
+ case QSOperator::BitXor: return OpBitXor;
+ case QSOperator::Div: return OpDiv;
+ case QSOperator::Equal: return OpEqual;
+ case QSOperator::Ge: return OpGe;
+ case QSOperator::Gt: return OpGt;
+ case QSOperator::Le: return OpLe;
+ case QSOperator::LShift: return OpLShift;
+ case QSOperator::Lt: return OpLt;
+ case QSOperator::Mod: return OpMod;
+ case QSOperator::Mul: return OpMul;
+ case QSOperator::NotEqual: return OpNotEqual;
+ case QSOperator::Or: return OpOr;
+ case QSOperator::RShift: return OpRShift;
+ case QSOperator::StrictEqual: return OpStrictEqual;
+ case QSOperator::StrictNotEqual: return OpStrictNotEqual;
+ case QSOperator::Sub: return OpSub;
+ case QSOperator::URShift: return OpURShift;
+ default: return OpInvalid;
+ }
+}
+
+void Const::dump(QTextStream &out)
+{
+ out << value;
+}
+
+void String::dump(QTextStream &out)
+{
+ out << '"' << escape(value) << '"';
+}
+
+QString String::escape(const QString &s)
+{
+ QString r;
+ foreach (const QChar &ch, s) {
+ if (ch == QLatin1Char('\n'))
+ r += QLatin1String("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QLatin1String("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QLatin1String("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QLatin1String("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QLatin1String("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column)
+: Expr(type)
+ , base(base)
+ , id(id)
+ , symbol(symbol)
+ , ptr(0)
+ , index(-1)
+ , storage(MemberStorage)
+ , builtin(NoBuiltinSymbol)
+ , line(line)
+ , column(column)
+{
+ if (id.length() == 8 && id == QLatin1String("Math.sin")) {
+ builtin = MathSinBultinFunction;
+ } else if (id.length() == 8 && id == QLatin1String("Math.cos")) {
+ builtin = MathCosBultinFunction;
+ } else if (id.length() == 10 && id == QLatin1String("Math.round")) {
+ builtin = MathRoundBultinFunction;
+ } else if (id.length() == 10 && id == QLatin1String("Math.floor)")) {
+ builtin = MathFloorBultinFunction;
+ } else if (id.length() == 7 && id == QLatin1String("Math.PI")) {
+ builtin = MathPIBuiltinConstant;
+ type = RealType;
+ }
+}
+
+void Name::dump(QTextStream &out)
+{
+ if (base) {
+ base->dump(out);
+ out << '.';
+ }
+
+ out << id;
+}
+
+void Temp::dump(QTextStream &out)
+{
+ out << 't' << index;
+}
+
+void Unop::dump(QTextStream &out)
+{
+ out << opname(op);
+ expr->dump(out);
+}
+
+Type Unop::typeForOp(AluOp op, Expr *expr)
+{
+ switch (op) {
+ case OpIfTrue: return BoolType;
+ case OpNot: return BoolType;
+
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return maxType(expr->type, RealType);
+
+ default:
+ break;
+ }
+
+ return InvalidType;
+}
+
+void Binop::dump(QTextStream &out)
+{
+ left->dump(out);
+ out << ' ' << opname(op) << ' ';
+ right->dump(out);
+}
+
+Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
+{
+ if (! (left && right))
+ return InvalidType;
+
+ switch (op) {
+ case OpInvalid:
+ return InvalidType;
+
+ // unary operators
+ case OpIfTrue:
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return InvalidType;
+
+ // bit fields
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ return IntType;
+
+ case OpAdd:
+ if (left->type == StringType)
+ return StringType;
+ return RealType;
+
+ case OpSub:
+ case OpMul:
+ case OpDiv:
+ case OpMod:
+ return RealType;
+
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ return IntType;
+
+ case OpAnd:
+ case OpOr:
+ return BoolType;
+
+ case OpGt:
+ case OpLt:
+ case OpGe:
+ case OpLe:
+ case OpEqual:
+ case OpNotEqual:
+ case OpStrictEqual:
+ case OpStrictNotEqual:
+ return BoolType;
+ } // switch
+
+ return InvalidType;
+}
+
+void Call::dump(QTextStream &out)
+{
+ base->dump(out);
+ out << '(';
+ for (int i = 0; i < args.size(); ++i) {
+ if (i)
+ out << ", ";
+ args.at(i)->dump(out);
+ }
+ out << ')';
+}
+
+Type Call::typeForFunction(Expr *base)
+{
+ if (! base)
+ return InvalidType;
+
+ if (Name *name = base->asName()) {
+ switch (name->builtin) {
+ case MathSinBultinFunction:
+ case MathCosBultinFunction:
+ return RealType;
+
+ case MathRoundBultinFunction:
+ case MathFloorBultinFunction:
+ return IntType;
+
+ case NoBuiltinSymbol:
+ case MathPIBuiltinConstant:
+ break;
+ }
+ } // switch
+
+ return InvalidType;
+}
+
+void Exp::dump(QTextStream &out, Mode)
+{
+ out << "(void) ";
+ expr->dump(out);
+ out << ';';
+}
+
+void Move::dump(QTextStream &out, Mode)
+{
+ target->dump(out);
+ out << " = ";
+ if (source->type != target->type)
+ out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
+ source->dump(out);
+ if (source->type != target->type)
+ out << ')';
+ out << ';';
+}
+
+void Jump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "goto " << 'L' << target << ';';
+}
+
+void CJump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "if (";
+ cond->dump(out);
+ out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
+}
+
+void Ret::dump(QTextStream &out, Mode)
+{
+ out << "return";
+ if (expr) {
+ out << ' ';
+ expr->dump(out);
+ }
+ out << ';';
+}
+
+Function::~Function()
+{
+ qDeleteAll(basicBlocks);
+ qDeleteAll(temps);
+}
+
+BasicBlock *Function::newBasicBlock()
+{
+ const int index = basicBlocks.size();
+ return i(new BasicBlock(this, index));
+}
+
+void Function::dump(QTextStream &out)
+{
+ QString fname;
+ if (name)
+ fname = name->asString();
+ else
+ fname = QLatin1String("$anonymous");
+ out << "function " << fname << "() {" << endl;
+ foreach (BasicBlock *bb, basicBlocks) {
+ bb->dump(out);
+ }
+ out << '}' << endl;
+}
+
+Temp *BasicBlock::TEMP(Type type, int index)
+{
+ return function->e(new Temp(type, index));
+}
+
+Temp *BasicBlock::TEMP(Type type)
+{
+ return TEMP(type, function->tempCount++);
+}
+
+Expr *BasicBlock::CONST(double value)
+{
+ return CONST(IR::RealType, value);
+}
+
+Expr *BasicBlock::CONST(Type type, double value)
+{
+ return function->e(new Const(type, value));
+}
+
+Expr *BasicBlock::STRING(const QString &value)
+{
+ return function->e(new String(value));
+}
+
+Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
+{
+ return NAME(0, id, line, column);
+}
+
+Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
+{
+ return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column));
+}
+
+Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = SYMBOL(/*base = */ 0, type, id, meta, index, line, column);
+ name->storage = storage;
+ return name;
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ name->storage = storage;
+ return function->e(name);
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ return function->e(name);
+}
+
+Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::ObjectType, id, Name::IdObject, line, column);
+ name->idObject = object;
+ name->index = object->idIndex;
+ name->storage = Name::IdStorage;
+ return function->e(name);
+}
+
+Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::AttachType, id, Name::AttachType, line, column);
+ name->declarativeType = attachType;
+ name->storage = storage;
+ return function->e(name);
+}
+
+
+Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ return function->e(new Unop(op, expr));
+}
+
+Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
+{
+ if (left && right) {
+ if (Const *c1 = left->asConst()) {
+ if (Const *c2 = right->asConst()) {
+ switch (op) {
+ case OpAdd: return CONST(c1->value + c2->value);
+ case OpAnd: return CONST(c1->value ? c2->value : 0);
+ case OpBitAnd: return CONST(int(c1->value) & int(c2->value));
+ case OpBitOr: return CONST(int(c1->value) | int(c2->value));
+ case OpBitXor: return CONST(int(c1->value) ^ int(c2->value));
+ case OpDiv: return CONST(c1->value / c2->value);
+ case OpEqual: return CONST(c1->value == c2->value);
+ case OpGe: return CONST(c1->value >= c2->value);
+ case OpGt: return CONST(c1->value > c2->value);
+ case OpLe: return CONST(c1->value <= c2->value);
+ case OpLShift: return CONST(int(c1->value) << int(c2->value));
+ case OpLt: return CONST(c1->value < c2->value);
+ case OpMod: return CONST(::fmod(c1->value, c2->value));
+ case OpMul: return CONST(c1->value * c2->value);
+ case OpNotEqual: return CONST(c1->value != c2->value);
+ case OpOr: return CONST(c1->value ? c1->value : c2->value);
+ case OpRShift: return CONST(int(c1->value) >> int(c2->value));
+ case OpStrictEqual: return CONST(c1->value == c2->value);
+ case OpStrictNotEqual: return CONST(c1->value != c2->value);
+ case OpSub: return CONST(c1->value - c2->value);
+ case OpURShift: return CONST(unsigned(c1->value) >> int(c2->value));
+
+ case OpIfTrue: // unary ops
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ case OpInvalid:
+ break;
+ }
+ }
+ }
+ }
+
+ return function->e(new Binop(op, left, right));
+}
+
+Expr *BasicBlock::CALL(Expr *base, const QVector<Expr *> &args)
+{
+ return function->e(new Call(base, args));
+}
+
+Stmt *BasicBlock::EXP(Expr *expr)
+{
+ return i(new Exp(expr));
+}
+
+Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
+{
+ return i(new Move(target, source, isMoveForReturn));
+}
+
+Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Jump(target));
+}
+
+Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ if (isTerminated())
+ return 0;
+ return i(new CJump(cond, iftrue, iffalse));
+}
+
+Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Ret(expr, type, line, column));
+}
+
+void BasicBlock::dump(QTextStream &out)
+{
+ out << 'L' << this << ':' << endl;
+ foreach (Stmt *s, statements) {
+ out << '\t';
+ s->dump(out);
+ out << endl;
+ }
+}
+
+void Module::dump(QTextStream &out)
+{
+ foreach (Function *fun, functions) {
+ fun->dump(out);
+ out << endl;
+ }
+}
+
+#ifdef DEBUG_IR_STRUCTURE
+
+static const char *symbolname(Name::Symbol s)
+{
+ switch (s) {
+ case Name::Unbound:
+ return "Unbound";
+ case Name::IdObject:
+ return "IdObject";
+ case Name::AttachType:
+ return "AttachType";
+ case Name::Object:
+ return "Object";
+ case Name::Property:
+ return "Property";
+ case Name::Slot:
+ return "Slot";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "Unknown";
+ }
+}
+
+static const char *storagename(Name::Storage s)
+{
+ switch (s) {
+ case Name::MemberStorage:
+ return "MemberStorage";
+ case Name::IdStorage:
+ return "IdStorage";
+ case Name::RootStorage:
+ return "RootStorage";
+ case Name::ScopeStorage:
+ return "ScopeStorage";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "UnknownStorage";
+ }
+}
+
+IRDump::IRDump()
+: indentSize(0)
+{
+}
+
+void IRDump::inc()
+{
+ indentSize++;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec()
+{
+ indentSize--;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec();
+
+void IRDump::expression(QDeclarativeJS::IR::Expr *e)
+{
+ inc();
+
+ e->accept(this);
+
+ dec();
+}
+
+void IRDump::basicblock(QDeclarativeJS::IR::BasicBlock *b)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "BasicBlock " << b << " {";
+ for (int ii = 0; ii < b->statements.count(); ++ii) {
+ statement(b->statements.at(ii));
+ if (ii != (b->statements.count() - 1))
+ qWarning();
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+void IRDump::statement(QDeclarativeJS::IR::Stmt *s)
+{
+ inc();
+
+ s->accept(this);
+
+ dec();
+}
+
+void IRDump::function(QDeclarativeJS::IR::Function *f)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "Function {";
+ for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
+ basicblock(f->basicBlocks.at(ii));
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+const char *IRDump::indent()
+{
+ return indentData.constData();
+}
+
+void IRDump::visitConst(QDeclarativeJS::IR::Const *e)
+{
+ qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+void IRDump::visitString(QDeclarativeJS::IR::String *e)
+{
+ qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+static void namedumprecur(QDeclarativeJS::IR::Name *e, const char *indent)
+{
+ if (e->base) namedumprecur(e->base, indent);
+ qWarning().nospace() << indent << " { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << "}";
+}
+
+void IRDump::visitName(QDeclarativeJS::IR::Name *e)
+{
+ qWarning().nospace() << indent() << "Name:Expr {";
+ namedumprecur(e, indent());
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
+{
+ qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
+}
+
+void IRDump::visitUnop(QDeclarativeJS::IR::Unop *e)
+{
+ qWarning().nospace() << indent() << "Unop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " expr: {";
+ expression(e->expr);
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitBinop(QDeclarativeJS::IR::Binop *e)
+{
+ qWarning().nospace() << indent() << "Binop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " left: {";
+ inc();
+ expression(e->left);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " right: {";
+ inc();
+ expression(e->right);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitCall(QDeclarativeJS::IR::Call *e)
+{
+ Q_UNUSED(e);
+ qWarning().nospace() << indent() << "Exp::Call { }";
+}
+
+void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
+{
+ qWarning().nospace() << indent() << "Exp:Stmt {";
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitMove(QDeclarativeJS::IR::Move *s)
+{
+ qWarning().nospace() << indent() << "Move:Stmt {";
+ qWarning().nospace() << indent() << " isMoveForReturn: " << s->isMoveForReturn;
+ qWarning().nospace() << indent() << " target: {";
+ inc();
+ expression(s->target);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " source: {";
+ inc();
+ expression(s->source);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitJump(QDeclarativeJS::IR::Jump *s)
+{
+ qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
+}
+
+void IRDump::visitCJump(QDeclarativeJS::IR::CJump *s)
+{
+ qWarning().nospace() << indent() << "CJump:Stmt {";
+ qWarning().nospace() << indent() << " cond: {";
+ inc();
+ expression(s->cond);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << " iftrue: BasicBlock(" << s->iftrue << ")";
+ qWarning().nospace() << indent() << " iffalse: BasicBlock(" << s->iffalse << ")";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitRet(QDeclarativeJS::IR::Ret *s)
+{
+ qWarning().nospace() << indent() << "Ret:Stmt {";
+ qWarning().nospace() << indent() << " type: " << typeName(s->type);
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+#endif
+
+} // end of namespace IR
+} // end of namespace QDeclarativeJS
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4ir_p.h b/src/declarative/qml/v4/qdeclarativev4ir_p.h
new file mode 100644
index 0000000000..93815e9154
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir_p.h
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IR_P_H
+#define QDECLARATIVEV4IR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qdeclarativejsast_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativev4compiler_p.h>
+
+#include <QtCore/qvector.h>
+
+// #define DEBUG_IR_STRUCTURE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTextStream;
+class QDeclarativeType;
+
+namespace QDeclarativeJS {
+
+namespace IR {
+
+struct BasicBlock;
+struct Function;
+struct Module;
+
+struct Stmt;
+struct Expr;
+
+// expressions
+struct Const;
+struct String;
+struct Name;
+struct Temp;
+struct Unop;
+struct Binop;
+struct Call;
+
+// statements
+struct Exp;
+struct Move;
+struct Jump;
+struct CJump;
+struct Ret;
+
+enum AluOp {
+ OpInvalid = 0,
+
+ OpIfTrue,
+ OpNot,
+ OpUMinus,
+ OpUPlus,
+ OpCompl,
+
+ OpBitAnd,
+ OpBitOr,
+ OpBitXor,
+
+ OpAdd,
+ OpSub,
+ OpMul,
+ OpDiv,
+ OpMod,
+
+ OpLShift,
+ OpRShift,
+ OpURShift,
+
+ OpGt,
+ OpLt,
+ OpGe,
+ OpLe,
+ OpEqual,
+ OpNotEqual,
+ OpStrictEqual,
+ OpStrictNotEqual,
+
+ OpAnd,
+ OpOr
+};
+AluOp binaryOperator(int op);
+
+enum Type {
+ InvalidType,
+ UndefinedType,
+ NullType,
+ VoidType,
+ StringType,
+ UrlType,
+ AnchorLineType,
+ SGAnchorLineType,
+ AttachType,
+ ObjectType,
+
+ FirstNumberType,
+ BoolType = FirstNumberType,
+ IntType,
+ RealType,
+ RealNaNType
+};
+Type maxType(IR::Type left, IR::Type right);
+
+struct ExprVisitor {
+ virtual ~ExprVisitor() {}
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitUnop(Unop *) {}
+ virtual void visitBinop(Binop *) {}
+ virtual void visitCall(Call *) {}
+};
+
+struct StmtVisitor {
+ virtual ~StmtVisitor() {}
+ virtual void visitExp(Exp *) {}
+ virtual void visitMove(Move *) {}
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *) {}
+ virtual void visitRet(Ret *) {}
+};
+
+struct Expr {
+ Type type;
+
+ Expr(Type type): type(type) {}
+ virtual ~Expr() {}
+ virtual void accept(ExprVisitor *) = 0;
+ virtual Const *asConst() { return 0; }
+ virtual String *asString() { return 0; }
+ virtual Name *asName() { return 0; }
+ virtual Temp *asTemp() { return 0; }
+ virtual Unop *asUnop() { return 0; }
+ virtual Binop *asBinop() { return 0; }
+ virtual Call *asCall() { return 0; }
+ virtual void dump(QTextStream &out) = 0;
+};
+
+struct Const: Expr {
+ double value;
+ Const(Type type, double value): Expr(type), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitConst(this); }
+ virtual Const *asConst() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct String: Expr {
+ QString value;
+ String(const QString &value): Expr(StringType), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitString(this); }
+ virtual String *asString() { return this; }
+
+ virtual void dump(QTextStream &out);
+ static QString escape(const QString &s);
+};
+
+enum BuiltinSymbol {
+ NoBuiltinSymbol,
+ MathSinBultinFunction,
+ MathCosBultinFunction,
+ MathRoundBultinFunction,
+ MathFloorBultinFunction,
+
+ MathPIBuiltinConstant
+};
+
+struct Name: Expr {
+ enum Symbol {
+ Unbound,
+ IdObject, // This is a load of a id object. Storage will always be IdStorage
+ AttachType, // This is a load of an attached object
+ Object, // XXX what is this for?
+ Property, // This is a load of a regular property
+ Slot // XXX what is this for?
+ };
+
+ enum Storage {
+ MemberStorage, // This is a property of a previously fetched object
+ IdStorage, // This is a load of a id object. Symbol will always be IdObject
+ RootStorage, // This is a property of the root object
+ ScopeStorage // This is a property of the scope object
+ };
+
+ Name *base;
+ QString id;
+ Symbol symbol;
+ union {
+ void *ptr;
+ const QMetaObject *meta;
+ const QDeclarativeType *declarativeType;
+ const QDeclarativeParser::Object *idObject;
+ };
+ int index;
+ Storage storage;
+ BuiltinSymbol builtin;
+ quint32 line;
+ quint32 column;
+
+ Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column);
+
+ inline bool is(Symbol s) const { return s == symbol; }
+ inline bool isNot(Symbol s) const { return s != symbol; }
+
+ virtual void accept(ExprVisitor *v) { v->visitName(this); }
+ virtual Name *asName() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Temp: Expr {
+ int index;
+ Temp(Type type, int index): Expr(type), index(index) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
+ virtual Temp *asTemp() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Unop: Expr {
+ AluOp op;
+ Expr *expr;
+
+ Unop(AluOp op, Expr *expr)
+ : Expr(typeForOp(op, expr)), op(op), expr(expr) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
+ virtual Unop *asUnop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *expr);
+};
+
+struct Binop: Expr {
+ AluOp op;
+ Expr *left;
+ Expr *right;
+ Binop(AluOp op, Expr *left, Expr *right)
+ : Expr(typeForOp(op, left, right)), op(op), left(left), right(right) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
+ virtual Binop *asBinop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *left, Expr *right);
+};
+
+struct Call: Expr {
+ Expr *base;
+ QVector<Expr *> args;
+
+ Call(Expr *base, const QVector<Expr *> &args)
+ : Expr(typeForFunction(base)), base(base), args(args) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitCall(this); }
+ virtual Call *asCall() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForFunction(Expr *base);
+};
+
+struct Stmt {
+ enum Mode {
+ HIR,
+ MIR
+ };
+
+ virtual ~Stmt() {}
+ virtual Stmt *asTerminator() { return 0; }
+
+ virtual void accept(StmtVisitor *) = 0;
+ virtual Exp *asExp() { return 0; }
+ virtual Move *asMove() { return 0; }
+ virtual Jump *asJump() { return 0; }
+ virtual CJump *asCJump() { return 0; }
+ virtual Ret *asRet() { return 0; }
+ virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+};
+
+struct Exp: Stmt {
+ Expr *expr;
+ Exp(Expr *expr): expr(expr) {}
+
+ virtual void accept(StmtVisitor *v) { v->visitExp(this); }
+ virtual Exp *asExp() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Move: Stmt {
+ Expr *target;
+ Expr *source;
+ bool isMoveForReturn;
+ Move(Expr *target, Expr *source, bool isMoveForReturn): target(target), source(source), isMoveForReturn(isMoveForReturn) {}
+
+ virtual void accept(StmtVisitor *v) { v->visitMove(this); }
+ virtual Move *asMove() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Jump: Stmt {
+ BasicBlock *target;
+ Jump(BasicBlock *target): target(target) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitJump(this); }
+ virtual Jump *asJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct CJump: Stmt {
+ Expr *cond;
+ BasicBlock *iftrue;
+ BasicBlock *iffalse;
+ CJump(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+ : cond(cond), iftrue(iftrue), iffalse(iffalse) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
+ virtual CJump *asCJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Ret: Stmt {
+ Expr *expr;
+ Type type;
+ quint32 line;
+ quint32 column;
+ Ret(Expr *expr, Type type, quint32 line, quint32 column): expr(expr), type(type), line(line), column(column) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitRet(this); }
+ virtual Ret *asRet() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Function {
+ Module *module;
+ const NameId *name;
+ int tempCount;
+ QVector<BasicBlock *> basicBlocks;
+ QVector<Expr *> temps;
+
+ template <typename BB> inline BB i(BB i) { basicBlocks.append(i); return i; }
+ template <typename E> inline E e(E e) { temps.append(e); return e; }
+
+ Function(Module *module, const NameId *name = 0): module(module), name(name), tempCount(0) {}
+ ~Function();
+
+ BasicBlock *newBasicBlock();
+
+ virtual void dump(QTextStream &out);
+};
+
+struct BasicBlock {
+ Function *function;
+ int index;
+ QVector<Stmt *> statements;
+ int offset;
+
+ BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {}
+ ~BasicBlock() { qDeleteAll(statements); }
+
+ template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+
+ inline bool isEmpty() const {
+ return statements.isEmpty();
+ }
+
+ inline Stmt *terminator() const {
+ if (! statements.isEmpty() && statements.last()->asTerminator() != 0)
+ return statements.last();
+ return 0;
+ }
+
+ inline bool isTerminated() const {
+ if (terminator() != 0)
+ return true;
+ return false;
+ }
+
+ Temp *TEMP(Type type, int index);
+ Temp *TEMP(Type type);
+
+ Expr *CONST(double value);
+ Expr *CONST(Type type, double value);
+ Expr *STRING(const QString &value);
+
+ Name *NAME(const QString &id, quint32 line, quint32 column);
+ Name *NAME(Name *base, const QString &id, quint32 line, quint32 column);
+ Name *SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column);
+ Name *ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage, quint32 line, quint32 column);
+
+ Expr *UNOP(AluOp op, Expr *expr);
+ Expr *BINOP(AluOp op, Expr *left, Expr *right);
+ Expr *CALL(Expr *base, const QVector<Expr *> &args);
+
+ Stmt *EXP(Expr *expr);
+ Stmt *MOVE(Expr *target, Expr *source, bool = false);
+
+ Stmt *JUMP(BasicBlock *target);
+ Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
+ Stmt *RET(Expr *expr, Type type, quint32 line, quint32 column);
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Module {
+ QVector<Function *> functions;
+
+ Module() {}
+ ~Module() { qDeleteAll(functions); }
+
+ template <typename BB> inline BB i(BB i) { functions.append(i); return i; }
+
+ Function *newFunction(const NameId *name = 0) { return i(new Function(this, name)); }
+
+ virtual void dump(QTextStream &out);
+};
+
+#ifdef DEBUG_IR_STRUCTURE
+struct IRDump : public ExprVisitor,
+ public StmtVisitor
+{
+public:
+ IRDump();
+
+ void expression(QDeclarativeJS::IR::Expr *);
+ void basicblock(QDeclarativeJS::IR::BasicBlock *);
+ void statement(QDeclarativeJS::IR::Stmt *);
+ void function(QDeclarativeJS::IR::Function *);
+protected:
+
+ const char *indent();
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ int indentSize;
+ QByteArray indentData;
+ void inc();
+ void dec();
+};
+#endif
+
+} // end of namespace IR
+
+} // end of namespace QDeclarativeJS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IR_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
new file mode 100644
index 0000000000..103d5ba0df
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
@@ -0,0 +1,1315 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativeglobalscriptclass_p.h> // For illegalNames
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+#include <private/qdeclarativetypenamecache_p.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, const QMetaObject *meta)
+{
+ switch (t) {
+ case QMetaType::Bool:
+ return IR::BoolType;
+
+ case QMetaType::Int:
+ return IR::IntType;
+
+ case QMetaType::QReal:
+ return IR::RealType;
+
+ case QMetaType::QString:
+ return IR::StringType;
+
+ case QMetaType::QUrl:
+ return IR::UrlType;
+
+ default:
+ if (t == qMetaTypeId<QDeclarativeAnchorLine>())
+ return IR::AnchorLineType;
+ else if (t == qMetaTypeId<QSGAnchorLine>())
+ return IR::SGAnchorLineType;
+ else if (const QMetaObject *m = engine->metaObjectForType(t)) {
+ meta = m;
+ return IR::ObjectType;
+ }
+
+ return IR::InvalidType;
+ }
+}
+
+QDeclarativeV4IRBuilder::QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *expr,
+ QDeclarativeEnginePrivate *engine)
+: m_expression(expr), m_engine(engine), _module(0), _function(0), _block(0), _discard(false)
+{
+}
+
+QDeclarativeJS::IR::Function *
+QDeclarativeV4IRBuilder::operator()(QDeclarativeJS::IR::Module *module,
+ QDeclarativeJS::AST::Node *ast)
+{
+ bool discarded = false;
+
+ qSwap(_module, module);
+
+ IR::Function *function = _module->newFunction();
+ IR::BasicBlock *block = function->newBasicBlock();
+
+ qSwap(_discard, discarded);
+ qSwap(_function, function);
+ qSwap(_block, block);
+
+ ExprResult r;
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *asExpr = ast->expressionCast()) {
+ r = expression(asExpr);
+ location = asExpr->firstSourceLocation();
+ } else if (AST::Statement *asStmt = ast->statementCast()) {
+ r = statement(asStmt);
+ location = asStmt->firstSourceLocation();
+ }
+
+ //_block->MOVE(_block->TEMP(IR::InvalidType), r.code);
+ if (r.code) {
+ const QMetaObject *m = 0;
+ const IR::Type targetType = irTypeFromVariantType(m_expression->property->type, m_engine, m);
+ if (targetType != r.type()) {
+ IR::Expr *x = _block->TEMP(targetType);
+ _block->MOVE(x, r, true);
+ r.code = x;
+ }
+ _block->RET(r.code, targetType, location.startLine, location.startColumn);
+ }
+
+ qSwap(_block, block);
+ qSwap(_function, function);
+ qSwap(_discard, discarded);
+
+ qSwap(_module, module);
+
+ return discarded?0:function;
+}
+
+bool QDeclarativeV4IRBuilder::buildName(QStringList &name,
+ AST::Node *node,
+ QList<AST::ExpressionNode *> *nodes)
+{
+ if (node->kind == AST::Node::Kind_IdentifierExpression) {
+ name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
+ if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
+ } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
+ AST::FieldMemberExpression *expr =
+ static_cast<AST::FieldMemberExpression *>(node);
+
+ if (!buildName(name, expr->base, nodes))
+ return false;
+
+ name << expr->name->asString();
+ if (nodes) *nodes << expr;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void QDeclarativeV4IRBuilder::discard()
+{
+ _discard = true;
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::expression(AST::ExpressionNode *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QDeclarativeV4IRBuilder::condition(AST::ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
+{
+ if (! ast)
+ return;
+ ExprResult r(iftrue, iffalse);
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.format != ExprResult::cx) {
+ if (! r.code)
+ discard();
+
+ Q_ASSERT(r.hint == ExprResult::cx);
+ Q_ASSERT(r.format == ExprResult::ex);
+
+ if (r.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, r);
+ r = t;
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpIfTrue, r), iftrue, iffalse);
+ }
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::statement(AST::Statement *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QDeclarativeV4IRBuilder::sourceElement(AST::SourceElement *ast)
+{
+ accept(ast);
+}
+
+void QDeclarativeV4IRBuilder::implicitCvt(ExprResult &expr, IR::Type type)
+{
+ if (expr.type() == type)
+ return; // nothing to do
+
+ IR::Expr *x = _block->TEMP(type);
+ _block->MOVE(x, expr.code);
+ expr.code = x;
+}
+
+// QML
+bool QDeclarativeV4IRBuilder::visit(AST::UiProgram *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImportList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImport *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiPublicMember *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectDefinition *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectInitializer *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiScriptBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiQualifiedId *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSignature *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormalList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormal *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// JS
+bool QDeclarativeV4IRBuilder::visit(AST::Program *ast)
+{
+ _function = _module->newFunction();
+ _block = _function->newBasicBlock();
+ accept(ast->elements);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SourceElements *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionSourceElement *)
+{
+ return true; // look inside
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementSourceElement *)
+{
+ return true; // look inside
+}
+
+// object literals
+bool QDeclarativeV4IRBuilder::visit(AST::PropertyNameAndValueList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// array literals
+bool QDeclarativeV4IRBuilder::visit(AST::ElementList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Elision *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// function calls
+bool QDeclarativeV4IRBuilder::visit(AST::ArgumentList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+// expressions
+bool QDeclarativeV4IRBuilder::visit(AST::ObjectLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThisExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast)
+{
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ const QString name = ast->name->asString();
+
+ if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
+ _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
+ } else if(m_engine->globalClass->illegalNames().contains(name) ) {
+ if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
+ return false;
+ } else if (const QDeclarativeParser::Object *obj = m_expression->ids.value(name)) {
+ IR::Name *code = _block->ID_OBJECT(name, obj, line, column);
+ if (obj == m_expression->component)
+ code->storage = IR::Name::RootStorage;
+ _expr.code = code;
+ } else if (QDeclarativeTypeNameCache::Data *typeNameData = m_expression->importCache->data(name)) {
+ if (typeNameData->importedScriptIndex != -1) {
+ // We don't support invoking imported scripts
+ } else if (typeNameData->type) {
+ _expr.code = _block->ATTACH_TYPE(name, typeNameData->type, IR::Name::ScopeStorage, line, column);
+ } else if (typeNameData->typeNamespace) {
+ // We don't support namespaces
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ } else {
+ bool found = false;
+
+ if (m_expression->context != m_expression->component) {
+ // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same
+ QDeclarativePropertyCache *cache = m_expression->context->synthCache;
+ const QMetaObject *metaObject = m_expression->context->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::ScopeStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ QDeclarativePropertyCache *cache = m_expression->component->synthCache;
+ const QMetaObject *metaObject = m_expression->component->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::RootStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unknown symbol:" << name;
+ }
+
+ if (_expr.code && _expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ if (_expr.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, _expr);
+ _expr.code = t;
+ }
+
+ _block->CJUMP(_expr.code, _expr.iftrue, _expr.iffalse);
+ _expr.code = 0;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NullExpression *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::NullType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TrueLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 1);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FalseLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteral *ast)
+{
+ // ### TODO: cx format
+ _expr.code = _block->STRING(ast->value->asString());
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NumericLiteral *ast)
+{
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(ast->value);
+ }
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::RegExpLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NestedExpression *)
+{
+ return true; // the value of the nested expression
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FieldMemberExpression *ast)
+{
+ if (IR::Expr *left = expression(ast->base)) {
+ if (IR::Name *baseName = left->asName()) {
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ QString name = ast->name->asString();
+
+ switch(baseName->symbol) {
+ case IR::Name::Unbound:
+ break;
+
+ case IR::Name::AttachType:
+ if (name.at(0).isUpper()) {
+ QByteArray utf8Name = name.toUtf8();
+ const char *enumName = utf8Name.constData();
+
+ const QMetaObject *meta = baseName->declarativeType->metaObject();
+ bool found = false;
+ for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
+ QMetaEnum e = meta->enumerator(ii);
+ for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
+ if (0 == strcmp(e.key(jj), enumName)) {
+ found = true;
+ _expr.code = _block->CONST(IR::IntType, e.value(jj));
+ }
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unresolved enum:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
+ QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta);
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final attached property:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, attachedMeta);
+ _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::IdObject: {
+ const QDeclarativeParser::Object *idObject = baseName->idObject;
+ QDeclarativePropertyCache *cache =
+ idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject());
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if (data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, idObject->metaObject());
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ idObject->metaObject(), data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Property:
+ if (baseName->type == IR::ObjectType) {
+ const QMetaObject *m =
+ m_engine->metaObjectForType(baseName->meta->property(baseName->index).userType());
+ QDeclarativePropertyCache *cache = m_engine->cache(m);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final property access:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta);
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ baseName->meta, data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Object:
+ case IR::Name::Slot:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CallExpression *ast)
+{
+ QStringList names;
+ QList<AST::ExpressionNode *> nameNodes;
+ if (buildName(names, ast->base, &nameNodes)) {
+ //ExprResult base = expression(ast->base);
+ const QString id = names.join(QLatin1String("."));
+ const quint32 line = nameNodes.last()->firstSourceLocation().startLine;
+ const quint32 column = nameNodes.last()->firstSourceLocation().startColumn;
+ IR::Expr *base = _block->NAME(id, line, column);
+
+ QVector<IR::Expr *> args;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next)
+ args.append(expression(it->expression));
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+ IR::Expr *call = _block->CALL(base, args);
+ _block->MOVE(r, call);
+ r->type = call->type;
+ _expr.code = r;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PostIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PostDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DeleteExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VoidExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TypeOfExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UnaryPlusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (expr.code->asConst() != 0) {
+ _expr = expr;
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUPlus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UnaryMinusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(-c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUMinus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TildeExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(~int(c->value));
+ return false;
+ }
+ IR::Expr *code = _block->UNOP(IR::OpCompl, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NotExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(!c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpNot, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+
+ } else if (expr.hint == ExprResult::cx) {
+ expr.format = ExprResult::cx;
+ _block->CJUMP(_block->UNOP(IR::OpNot, expr), _expr.iftrue, _expr.iffalse);
+ return false;
+ }
+
+ return false;
+}
+
+void QDeclarativeV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult right)
+{
+ if (IR::Type t = maxType(left.type(), right.type())) {
+ implicitCvt(left, t);
+ implicitCvt(right, t);
+
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ }
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::BinaryExpression *ast)
+{
+ switch (ast->op) {
+ case QSOperator::And: {
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ Q_ASSERT(_expr.iffalse != 0);
+ Q_ASSERT(_expr.iftrue != 0);
+
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ condition(ast->left, iftrue, _expr.iffalse);
+
+ _block = iftrue;
+ condition(ast->right, _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->left, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ _block = iffalse;
+ _block->MOVE(r, _block->CONST(0)); // ### use the right null value
+ _block->JUMP(endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+ _block->JUMP(endif);
+
+ _block = endif;
+
+ r->type = right.type(); // ### not exactly, it can be IR::BoolType.
+ _expr.code = r;
+ }
+ } break;
+
+ case QSOperator::Or: {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ ExprResult left = expression(ast->left);
+ IR::Temp *r = _block->TEMP(left.type());
+ _block->MOVE(r, left);
+
+ IR::Expr *cond = r;
+ if (r->type != IR::BoolType) {
+ cond = _block->TEMP(IR::BoolType);
+ _block->MOVE(cond, r);
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpNot, cond), iftrue, endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+
+ if (left.type() != right.type())
+ discard();
+
+ _expr.code = r;
+
+ _block = endif;
+ } break;
+
+ case QSOperator::Lt:
+ case QSOperator::Gt:
+ case QSOperator::Le:
+ case QSOperator::Ge: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == IR::StringType && right.type() == IR::StringType) {
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::NotEqual:
+ case QSOperator::Equal: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if ((left.type() == IR::NullType || left.type() == IR::UndefinedType) &&
+ (right.type() == IR::NullType || right.type() == IR::UndefinedType)) {
+ const bool isEq = ast->op == QSOperator::Equal;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ } else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
+ (left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ } else if (left.type() == IR::BoolType || right.type() == IR::BoolType) {
+ implicitCvt(left, IR::BoolType);
+ implicitCvt(right, IR::BoolType);
+ } else if (left.isValid() && right.isValid()) {
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::StrictEqual:
+ case QSOperator::StrictNotEqual: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == right.type()) {
+ binop(ast, left, right);
+ } else if (left.type() >= IR::BoolType && right.type() >= IR::BoolType) {
+ // left and right have numeric type (int or real)
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ const bool isEq = ast->op == QSOperator::StrictEqual;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ }
+ } break;
+
+ case QSOperator::BitAnd:
+ case QSOperator::BitOr:
+ case QSOperator::BitXor:
+ case QSOperator::LShift:
+ case QSOperator::RShift:
+ case QSOperator::URShift: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ implicitCvt(left, IR::IntType);
+ implicitCvt(right, IR::IntType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+
+ } break;
+
+ case QSOperator::Add: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ if (left.isPrimitive() && right.isPrimitive()) {
+ if (left.type() == IR::StringType || right.type() == IR::StringType) {
+ implicitCvt(left, IR::StringType);
+ implicitCvt(right, IR::StringType);
+ }
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::Div:
+ case QSOperator::Mod:
+ case QSOperator::Mul:
+ case QSOperator::Sub: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ IR::Type t = maxType(left.type(), right.type());
+ if (t >= IR::FirstNumberType) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ } break;
+
+ case QSOperator::In:
+ case QSOperator::InstanceOf:
+ case QSOperator::Assign:
+ case QSOperator::InplaceAnd:
+ case QSOperator::InplaceSub:
+ case QSOperator::InplaceDiv:
+ case QSOperator::InplaceAdd:
+ case QSOperator::InplaceLeftShift:
+ case QSOperator::InplaceMod:
+ case QSOperator::InplaceMul:
+ case QSOperator::InplaceOr:
+ case QSOperator::InplaceRightShift:
+ case QSOperator::InplaceURightShift:
+ case QSOperator::InplaceXor:
+ // yup, we don't do those.
+ break;
+ } // switch
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ConditionalExpression *ast)
+{
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = expression(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = expression(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Expression *ast)
+{
+ _block->EXP(expression(ast->left));
+ _expr = expression(ast->right);
+
+ return false;
+}
+
+
+// statements
+bool QDeclarativeV4IRBuilder::visit(AST::Block *ast)
+{
+ if (ast->statements && ! ast->statements->next) {
+ // we have one and only one statement
+ accept(ast->statements->statement);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclarationList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::EmptyStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ExpressionStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of this expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IfStatement *ast)
+{
+ if (! ast->ko) {
+ // This is an if statement without an else branch.
+ discard();
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = statement(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = statement(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DoWhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForEachStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForEachStatement *)
+{
+ discard();
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ContinueStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::BreakStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ReturnStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of the expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WithStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SwitchStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseBlock *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClauses *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DefaultClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LabelledStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThrowStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TryStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Catch *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Finally *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FormalParameterList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionBody *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DebuggerStatement *)
+{
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
new file mode 100644
index 0000000000..f0bfd6624c
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IRBUILDER_P_H
+#define QDECLARATIVEV4IRBUILDER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include "qdeclarativev4ir_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4IRBuilder : public QDeclarativeJS::AST::Visitor
+{
+public:
+ QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *, QDeclarativeEnginePrivate *);
+
+ QDeclarativeJS::IR::Function *operator()(QDeclarativeJS::IR::Module *, QDeclarativeJS::AST::Node *);
+
+protected:
+ struct ExprResult {
+ enum Format {
+ ex, // expression
+ cx // condition
+ };
+
+ QDeclarativeJS::IR::Expr *code;
+ QDeclarativeJS::IR::BasicBlock *iftrue;
+ QDeclarativeJS::IR::BasicBlock *iffalse;
+ Format hint; // requested format
+ Format format; // instruction format
+
+ ExprResult(QDeclarativeJS::IR::Expr *expr = 0)
+ : code(expr), iftrue(0), iffalse(0), hint(ex), format(ex) {}
+
+ ExprResult(QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse)
+ : code(0), iftrue(iftrue), iffalse(iffalse), hint(cx), format(ex) {}
+
+ inline QDeclarativeJS::IR::Type type() const { return code ? code->type : QDeclarativeJS::IR::InvalidType; }
+
+ inline QDeclarativeJS::IR::Expr *get() const { return code; }
+ inline operator QDeclarativeJS::IR::Expr *() const { return get(); }
+ inline QDeclarativeJS::IR::Expr *operator->() const { return get(); }
+ inline bool isValid() const { return code ? code->type != QDeclarativeJS::IR::InvalidType : false; }
+ inline bool is(QDeclarativeJS::IR::Type t) const { return type() == t; }
+ inline bool isNot(QDeclarativeJS::IR::Type t) const { return type() != t; }
+
+ bool isPrimitive() const {
+ switch (type()) {
+ case QDeclarativeJS::IR::UndefinedType: // ### TODO
+ case QDeclarativeJS::IR::NullType: // ### TODO
+ case QDeclarativeJS::IR::UrlType: // ### TODO
+ return false;
+
+ case QDeclarativeJS::IR::StringType:
+ case QDeclarativeJS::IR::BoolType:
+ case QDeclarativeJS::IR::IntType:
+ case QDeclarativeJS::IR::RealType:
+ case QDeclarativeJS::IR::RealNaNType:
+ return true;
+
+ default:
+ return false;
+ } // switch
+ }
+ };
+
+ inline void accept(QDeclarativeJS::AST::Node *ast) { QDeclarativeJS::AST::Node::accept(ast, this); }
+
+ ExprResult expression(QDeclarativeJS::AST::ExpressionNode *ast);
+ ExprResult statement(QDeclarativeJS::AST::Statement *ast);
+ void sourceElement(QDeclarativeJS::AST::SourceElement *ast);
+ void condition(QDeclarativeJS::AST::ExpressionNode *ast, QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse);
+ void binop(QDeclarativeJS::AST::BinaryExpression *ast, ExprResult left, ExprResult right);
+
+ void implicitCvt(ExprResult &expr, QDeclarativeJS::IR::Type type);
+
+ // QML
+ virtual bool visit(QDeclarativeJS::AST::UiProgram *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImportList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImport *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiPublicMember *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectDefinition *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectInitializer *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiScriptBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiQualifiedId *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSignature *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormalList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormal *ast);
+
+ // JS
+ virtual bool visit(QDeclarativeJS::AST::Program *ast);
+ virtual bool visit(QDeclarativeJS::AST::SourceElements *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementSourceElement *ast);
+
+ // object literals
+ virtual bool visit(QDeclarativeJS::AST::PropertyNameAndValueList *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteralPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteralPropertyName *ast);
+
+ // array literals
+ virtual bool visit(QDeclarativeJS::AST::ElementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::Elision *ast);
+
+ // function calls
+ virtual bool visit(QDeclarativeJS::AST::ArgumentList *ast);
+
+ // expressions
+ virtual bool visit(QDeclarativeJS::AST::ObjectLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThisExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NullExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TrueLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::FalseLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::RegExpLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NestedExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FieldMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::CallExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::DeleteExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::VoidExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TypeOfExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryPlusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryMinusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TildeExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NotExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::BinaryExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ConditionalExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::Expression *ast);
+
+ // statements
+ virtual bool visit(QDeclarativeJS::AST::Block *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclarationList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::EmptyStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ExpressionStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::IfStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::DoWhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ContinueStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::BreakStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ReturnStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WithStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::SwitchStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseBlock *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClauses *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::DefaultClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::LabelledStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThrowStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::TryStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::Catch *ast);
+ virtual bool visit(QDeclarativeJS::AST::Finally *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FormalParameterList *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionBody *ast);
+ virtual bool visit(QDeclarativeJS::AST::DebuggerStatement *ast);
+
+private:
+ bool buildName(QStringList &name, QDeclarativeJS::AST::Node *node,
+ QList<QDeclarativeJS::AST::ExpressionNode *> *nodes);
+ void discard();
+
+ const QDeclarativeV4Compiler::Expression *m_expression;
+ QDeclarativeEnginePrivate *m_engine;
+
+ QDeclarativeJS::IR::Module *_module;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ bool _discard;
+
+ ExprResult _expr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IRBUILDER_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4program_p.h b/src/declarative/qml/v4/qdeclarativev4program_p.h
new file mode 100644
index 0000000000..d036bd6f73
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4program_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4PROGRAM_P_H
+#define QDECLARATIVEV4PROGRAM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeV4Program {
+ quint32 bindings;
+ quint32 dataLength;
+ quint32 signalTableOffset;
+ quint32 exceptionDataOffset;
+ quint16 subscriptions;
+ quint16 identifiers;
+ quint16 instructionCount;
+
+ struct BindingReference {
+ quint32 binding;
+ quint32 blockMask;
+ };
+
+ struct BindingReferenceList {
+ quint32 count;
+ BindingReference bindings[];
+ };
+
+ inline const char *data() const;
+ inline const char *instructions() const;
+ inline BindingReferenceList *signalTable(int signalIndex) const;
+};
+
+enum QDeclarativeRegisterType {
+ UndefinedType,
+ QObjectStarType,
+ QRealType,
+ IntType,
+ BoolType,
+
+ PODValueType,
+
+ FirstCleanupType,
+ QStringType = FirstCleanupType,
+ QUrlType,
+ QVariantType,
+};
+
+const char *QDeclarativeV4Program::data() const
+{
+ return ((const char *)this) + sizeof(QDeclarativeV4Program);
+}
+
+const char *QDeclarativeV4Program::instructions() const
+{
+ return (const char *)(data() + dataLength);
+}
+
+QDeclarativeV4Program::BindingReferenceList *QDeclarativeV4Program::signalTable(int signalIndex) const
+{
+ quint32 *signalTable = (quint32 *)(data() + signalTableOffset);
+ return (BindingReferenceList *)(signalTable + signalTable[signalIndex]);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4PROGRAM_P_H
+
diff --git a/src/declarative/qml/v4/v4.pri b/src/declarative/qml/v4/v4.pri
new file mode 100644
index 0000000000..085f0ae443
--- /dev/null
+++ b/src/declarative/qml/v4/v4.pri
@@ -0,0 +1,17 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qdeclarativev4compiler_p.h \
+ $$PWD/qdeclarativev4compiler_p_p.h \
+ $$PWD/qdeclarativev4ir_p.h \
+ $$PWD/qdeclarativev4irbuilder_p.h \
+ $$PWD/qdeclarativev4instruction_p.h \
+ $$PWD/qdeclarativev4bindings_p.h \
+ $$PWD/qdeclarativev4program_p.h \
+
+SOURCES += \
+ $$PWD/qdeclarativev4compiler.cpp \
+ $$PWD/qdeclarativev4ir.cpp \
+ $$PWD/qdeclarativev4irbuilder.cpp \
+ $$PWD/qdeclarativev4instruction.cpp \
+ $$PWD/qdeclarativev4bindings.cpp \