aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/ftw/ftw.pri1
-rw-r--r--src/declarative/qml/ftw/qfieldlist_p.h1
-rw-r--r--src/declarative/qml/ftw/qrecyclepool_p.h220
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h51
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp132
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h84
-rw-r--r--src/declarative/qml/v4/qv4compiler.cpp8
-rw-r--r--src/declarative/qml/v4/qv4compiler_p.h1
-rw-r--r--src/declarative/qml/v8/qv8contextwrapper.cpp10
-rw-r--r--src/declarative/qml/v8/qv8qobjectwrapper.cpp20
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml5
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml6
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp1
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.h20
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp46
16 files changed, 476 insertions, 132 deletions
diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri
index c7750468d9..63399927e7 100644
--- a/src/declarative/qml/ftw/ftw.pri
+++ b/src/declarative/qml/ftw/ftw.pri
@@ -11,6 +11,7 @@ HEADERS += \
$$PWD/qdeclarativethread_p.h \
$$PWD/qfinitestack_p.h \
$$PWD/qrecursionwatcher_p.h \
+ $$PWD/qrecyclepool_p.h \
SOURCES += \
$$PWD/qintrusivelist.cpp \
diff --git a/src/declarative/qml/ftw/qfieldlist_p.h b/src/declarative/qml/ftw/qfieldlist_p.h
index f0efd16a20..c6b432324c 100644
--- a/src/declarative/qml/ftw/qfieldlist_p.h
+++ b/src/declarative/qml/ftw/qfieldlist_p.h
@@ -107,6 +107,7 @@ N *QFieldList<N, nextMember>::takeFirst()
Q_ASSERT(_first == 0);
_last = 0;
}
+ value->*nextMember = 0;
--_count;
}
return value;
diff --git a/src/declarative/qml/ftw/qrecyclepool_p.h b/src/declarative/qml/ftw/qrecyclepool_p.h
new file mode 100644
index 0000000000..f349996a22
--- /dev/null
+++ b/src/declarative/qml/ftw/qrecyclepool_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRECYCLEPOOL_P_H
+#define QRECYCLEPOOL_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+#define QRECYCLEPOOLCOOKIE 0x33218ADF
+
+template<typename T, int Step>
+class QRecyclePoolPrivate
+{
+public:
+ QRecyclePoolPrivate()
+ : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE),
+ currentPage(0), nextAllocated(0)
+ {
+ }
+
+ bool recyclePoolHold;
+ int outstandingItems;
+ quint32 cookie;
+
+ struct PoolType : public T {
+ union {
+ QRecyclePoolPrivate<T, Step> *pool;
+ PoolType *nextAllocated;
+ };
+ };
+
+ struct Page {
+ Page *nextPage;
+ unsigned int free;
+ union {
+ char array[Step * sizeof(PoolType)];
+ qint64 q_for_alignment_1;
+ double q_for_alignment_2;
+ };
+ };
+
+ Page *currentPage;
+ PoolType *nextAllocated;
+
+ inline T *allocate();
+ static inline void dispose(T *);
+ inline void releaseIfPossible();
+};
+
+template<typename T, int Step = 1024>
+class QRecyclePool
+{
+public:
+ inline QRecyclePool();
+ inline ~QRecyclePool();
+
+ inline T *New();
+ template<typename T1>
+ inline T *New(const T1 &);
+ template<typename T1>
+ inline T *New(T1 &);
+
+ static inline void Delete(T *);
+
+private:
+ QRecyclePoolPrivate<T, Step> *d;
+};
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::QRecyclePool()
+: d(new QRecyclePoolPrivate<T, Step>())
+{
+}
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::~QRecyclePool()
+{
+ d->recyclePoolHold = false;
+ d->releaseIfPossible();
+}
+
+template<typename T, int Step>
+T *QRecyclePool<T, Step>::New()
+{
+ T *rv = d->allocate();
+ new (rv) T;
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(const T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePool<T, Step>::Delete(T *t)
+{
+ t->~T();
+ QRecyclePoolPrivate<T, Step>::dispose(t);
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::releaseIfPossible()
+{
+ if (recyclePoolHold || outstandingItems)
+ return;
+
+ Page *p = currentPage;
+ while (p) {
+ Page *n = p->nextPage;
+ qFree(p);
+ p = n;
+ }
+
+ delete this;
+}
+
+template<typename T, int Step>
+T *QRecyclePoolPrivate<T, Step>::allocate()
+{
+ PoolType *rv = 0;
+ if (nextAllocated) {
+ rv = nextAllocated;
+ nextAllocated = rv->nextAllocated;
+ } else if (currentPage && currentPage->free) {
+ rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType));
+ currentPage->free--;
+ } else {
+ Page *p = (Page *)qMalloc(sizeof(Page));
+ p->nextPage = currentPage;
+ p->free = Step;
+ currentPage = p;
+
+ rv = (PoolType *)currentPage->array;
+ currentPage->free--;
+ }
+
+ rv->pool = this;
+ ++outstandingItems;
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::dispose(T *t)
+{
+ PoolType *pt = static_cast<PoolType *>(t);
+ Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE);
+
+ QRecyclePoolPrivate<T, Step> *This = pt->pool;
+ pt->nextAllocated = This->nextAllocated;
+ This->nextAllocated = pt;
+ --This->outstandingItems;
+ This->releaseIfPossible();
+}
+
+QT_END_NAMESPACE
+
+#endif // QRECYCLEPOOL_P_H
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 86c944f65e..1323669fc7 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -332,7 +332,7 @@ the same object as is returned from the Qt.include() call.
QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
-: captureProperties(false), rootContext(0), isDebugging(false),
+: propertyCapture(0), rootContext(0), isDebugging(false),
outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
cleanup(0), erroredBindings(0), inProgressCreations(0),
workerScriptEngine(0), activeVME(0),
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 88eda390e3..a678a4588c 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -69,6 +69,7 @@
#include "qdeclarativemetatype_p.h"
#include "qdeclarativedirparser_p.h"
#include <private/qintrusivelist_p.h>
+#include <private/qrecyclepool_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
@@ -103,6 +104,21 @@ class QSGTexture;
class QDeclarativeIncubator;
class QSGContext;
+// This needs to be declared here so that the pool for it can live in QDeclarativeEnginePrivate.
+// The inline method definitions are in qdeclarativeexpression_p.h
+class QDeclarativeJavaScriptExpressionGuard : public QDeclarativeNotifierEndpoint
+{
+public:
+ inline QDeclarativeJavaScriptExpressionGuard(QDeclarativeJavaScriptExpression *);
+
+ static inline void endpointCallback(QDeclarativeNotifierEndpoint *);
+ static inline QDeclarativeJavaScriptExpressionGuard *New(QDeclarativeJavaScriptExpression *e);
+ inline void Delete();
+
+ QDeclarativeJavaScriptExpression *expression;
+ QDeclarativeJavaScriptExpressionGuard *next;
+};
+
class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDeclarativeEngine)
@@ -112,19 +128,18 @@ public:
void init();
- struct CapturedProperty {
- CapturedProperty(QObject *o, int c, int n)
- : object(o), coreIndex(c), notifier(0), notifyIndex(n) {}
- CapturedProperty(QDeclarativeNotifier *n)
- : object(0), coreIndex(-1), notifier(n), notifyIndex(-1) {}
-
- QObject *object;
- int coreIndex;
- QDeclarativeNotifier *notifier;
- int notifyIndex;
+ class PropertyCapture {
+ public:
+ inline virtual ~PropertyCapture() {}
+ virtual void captureProperty(QDeclarativeNotifier *) = 0;
+ virtual void captureProperty(QObject *, int, int) = 0;
};
- bool captureProperties;
- QPODVector<CapturedProperty> capturedProperties;
+
+ PropertyCapture *propertyCapture;
+ inline void captureProperty(QDeclarativeNotifier *);
+ inline void captureProperty(QObject *, int, int);
+
+ QRecyclePool<QDeclarativeJavaScriptExpressionGuard> jsExpressionGuardPool;
QDeclarativeContext *rootContext;
bool isDebugging;
@@ -492,6 +507,18 @@ QDeclarativeEngine *QDeclarativeEnginePrivate::get(QDeclarativeEnginePrivate *p)
return p->q_func();
}
+void QDeclarativeEnginePrivate::captureProperty(QDeclarativeNotifier *n)
+{
+ if (propertyCapture)
+ propertyCapture->captureProperty(n);
+}
+
+void QDeclarativeEnginePrivate::captureProperty(QObject *o, int c, int n)
+{
+ if (propertyCapture)
+ propertyCapture->captureProperty(o, c, n);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEENGINE_P_H
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index bfa9c58d86..fa899cf814 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -70,12 +70,14 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression()
: m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0),
- m_scopeObject(0)
+ m_scopeObject(0), guardCapture(0)
{
}
QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
{
+ if (guardCapture) guardCapture->expression = 0;
+ clearGuards();
}
QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
@@ -396,12 +398,12 @@ void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> mes
void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
m_notifyOnValueChanged = v;
- if (!v) guardList.clear();
+ if (!v) clearGuards();
}
void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
{
- guardList.clear();
+ clearGuards();
}
v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
@@ -415,12 +417,15 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
- bool lastCaptureProperties = ep->captureProperties;
- QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
- ep->captureProperties = notifyOnValueChanged();
+ Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+ GuardCapture capture(this);
- if (ep->capturedProperties.count())
- ep->capturedProperties.copyAndClear(lastCapturedProperties);
+ QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = notifyOnValueChanged()?&capture:0;
+
+
+ if (notifyOnValueChanged())
+ capture.guards.copyAndClear(activeGuards);
QDeclarativeContextData *lastSharedContext = 0;
QObject *lastSharedScope = 0;
@@ -471,79 +476,90 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
ep->sharedScope = lastSharedScope;
}
- if (!watcher.wasDeleted() && notifyOnValueChanged()) {
- guardList.updateGuards(this, ep->capturedProperties);
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->count(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = 0;
}
- if (lastCapturedProperties.count())
- lastCapturedProperties.copyAndClear(ep->capturedProperties);
- else
- ep->capturedProperties.clear();
+ while (Guard *g = capture.guards.takeFirst())
+ g->Delete();
- ep->captureProperties = lastCaptureProperties;
+ ep->propertyCapture = lastPropertyCapture;
return result;
}
-void
-QDeclarativeJavaScriptExpression::GuardList::updateGuards(QDeclarativeJavaScriptExpression *expression,
- const CapturedProperties &properties)
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n)
{
- if (properties.count() == 0) {
- clear();
- return;
- }
+ if (expression) {
- if (properties.count() != length) {
- Endpoint *newGuardList = new Endpoint[properties.count()];
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(n))
+ guards.takeFirst()->Delete();
- for (int ii = 0; ii < qMin(length, properties.count()); ++ii)
- endpoints[ii].copyAndClear(newGuardList[ii]);
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(n));
+ } else {
+ g = Guard::New(expression);
+ g->connect(n);
+ }
- delete [] endpoints;
- endpoints = newGuardList;
- length = properties.count();
+ expression->activeGuards.append(g);
}
+}
- bool outputWarningHeader = false;
- for (int ii = 0; ii < properties.count(); ++ii) {
- Endpoint &guard = endpoints[ii];
- const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
-
- guard.expression = expression;
-
- if (property.notifier != 0) {
-
- if (guard.isConnected(property.notifier)) {
- guard.cancelNotify();
- } else {
- guard.connect(property.notifier);
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+ if (expression) {
+ if (n == -1) {
+ if (!errorString) {
+ errorString = new QStringList;
+ QString preamble = QLatin1String("QDeclarativeExpression: Expression ") +
+ expression->expressionIdentifier() +
+ QLatin1String(" depends on non-NOTIFYable properties:");
+ errorString->append(preamble);
}
- } else if (property.notifyIndex != -1) {
-
- if (guard.isConnected(property.object, property.notifyIndex)) {
- guard.cancelNotify();
- } else {
- guard.connect(property.object, property.notifyIndex);
- }
+ const QMetaObject *metaObj = o->metaObject();
+ QMetaProperty metaProp = metaObj->property(c);
+ QString error = QLatin1String(" ") +
+ QString::fromUtf8(metaObj->className()) +
+ QLatin1String("::") +
+ QString::fromUtf8(metaProp.name());
+ errorString->append(error);
} else {
- if (!outputWarningHeader) {
- QString e = expression->expressionIdentifier();
- outputWarningHeader = true;
- qWarning() << "QDeclarativeExpression: Expression" << qPrintable(e)
- << "depends on non-NOTIFYable properties:";
- }
- const QMetaObject *metaObj = property.object->metaObject();
- QMetaProperty metaProp = metaObj->property(property.coreIndex);
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
+ guards.takeFirst()->Delete();
+
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(o, n));
+ } else {
+ g = Guard::New(expression);
+ g->connect(o, n);
+ }
- qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
+ expression->activeGuards.append(g);
}
}
}
+void QDeclarativeJavaScriptExpression::clearGuards()
+{
+ while (Guard *g = activeGuards.takeFirst())
+ g->Delete();
+}
+
// Must be called with a valid handle scope
v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
{
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
index 4e31efb806..65b07ca7e8 100644
--- a/src/declarative/qml/qdeclarativeexpression_p.h
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -55,10 +55,10 @@
#include "qdeclarativeexpression.h"
-#include <private/qdeclarativeengine_p.h>
-#include <private/qdeclarativeguard_p.h>
-
#include <private/qv8engine_p.h>
+#include <private/qfieldlist_p.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeengine_p.h>
QT_BEGIN_NAMESPACE
@@ -164,28 +164,28 @@ private:
QObject *m_scopeObject;
- class GuardList {
- public:
- inline GuardList();
- inline ~GuardList();
- void inline clear();
-
- typedef QPODVector<QDeclarativeEnginePrivate::CapturedProperty> CapturedProperties;
- void updateGuards(QDeclarativeJavaScriptExpression *, const CapturedProperties &properties);
-
- private:
- struct Endpoint : public QDeclarativeNotifierEndpoint {
- Endpoint() : expression(0) { callback = &endpointCallback; }
- static void endpointCallback(QDeclarativeNotifierEndpoint *e) {
- static_cast<Endpoint *>(e)->expression->expressionChanged();
- }
- QDeclarativeJavaScriptExpression *expression;
- };
-
- Endpoint *endpoints;
- int length;
+ typedef QDeclarativeJavaScriptExpressionGuard Guard;
+
+ struct GuardCapture : public QDeclarativeEnginePrivate::PropertyCapture {
+ GuardCapture(QDeclarativeJavaScriptExpression *e) : expression(e), errorString(0) {
+ }
+ ~GuardCapture() {
+ Q_ASSERT(guards.isEmpty());
+ Q_ASSERT(errorString == 0);
+ }
+
+ virtual void captureProperty(QDeclarativeNotifier *);
+ virtual void captureProperty(QObject *, int, int);
+
+ QDeclarativeJavaScriptExpression *expression;
+ QFieldList<Guard, &Guard::next> guards;
+ QStringList *errorString;
};
- GuardList guardList;
+
+ QFieldList<Guard, &Guard::next> activeGuards;
+ GuardCapture *guardCapture;
+
+ void clearGuards();
};
class QDeclarativeExpression;
@@ -302,36 +302,42 @@ QString QDeclarativeJavaScriptExpression::expressionIdentifier()
return QString();
}
-QDeclarativeJavaScriptExpression::GuardList::GuardList()
-: endpoints(0), length(0)
+QDeclarativeExpressionPrivate *QDeclarativeExpressionPrivate::get(QDeclarativeExpression *expr)
{
+ return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
}
-QDeclarativeJavaScriptExpression::GuardList::~GuardList()
-{
- clear();
+QDeclarativeExpression *QDeclarativeExpressionPrivate::get(QDeclarativeExpressionPrivate *expr)
+{
+ return expr->q_func();
}
-void QDeclarativeJavaScriptExpression::GuardList::clear()
+QString QDeclarativeExpressionPrivate::expressionIdentifier()
+{
+ return QLatin1String("\"") + expression + QLatin1String("\"");
+}
+
+QDeclarativeJavaScriptExpressionGuard::QDeclarativeJavaScriptExpressionGuard(QDeclarativeJavaScriptExpression *e)
+: expression(e), next(0)
{
- delete [] endpoints;
- endpoints = 0;
- length = 0;
+ callback = &endpointCallback;
}
-QDeclarativeExpressionPrivate *QDeclarativeExpressionPrivate::get(QDeclarativeExpression *expr)
+void QDeclarativeJavaScriptExpressionGuard::endpointCallback(QDeclarativeNotifierEndpoint *e)
{
- return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
+ static_cast<QDeclarativeJavaScriptExpressionGuard *>(e)->expression->expressionChanged();
}
-QDeclarativeExpression *QDeclarativeExpressionPrivate::get(QDeclarativeExpressionPrivate *expr)
+QDeclarativeJavaScriptExpressionGuard *
+QDeclarativeJavaScriptExpressionGuard::New(QDeclarativeJavaScriptExpression *e)
{
- return expr->q_func();
+ Q_ASSERT(e);
+ return QDeclarativeEnginePrivate::get(e->context()->engine)->jsExpressionGuardPool.New(e);
}
-QString QDeclarativeExpressionPrivate::expressionIdentifier()
+void QDeclarativeJavaScriptExpressionGuard::Delete()
{
- return QLatin1String("\"") + expression + QLatin1String("\"");
+ QRecyclePool<QDeclarativeJavaScriptExpressionGuard>::Delete(this);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qv4compiler.cpp b/src/declarative/qml/v4/qv4compiler.cpp
index a9d2338307..857bceb460 100644
--- a/src/declarative/qml/v4/qv4compiler.cpp
+++ b/src/declarative/qml/v4/qv4compiler.cpp
@@ -59,6 +59,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
static bool qmlBindingsTest = false;
+static bool qmlEnableV4 = true;
using namespace QDeclarativeJS;
QV4CompilerPrivate::QV4CompilerPrivate()
@@ -1219,7 +1220,7 @@ int QV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate
if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
return -1;
- if (qmlDisableOptimizer())
+ if (qmlDisableOptimizer() || !qmlEnableV4)
return -1;
d->expression = &expression;
@@ -1341,4 +1342,9 @@ void QV4Compiler::enableBindingsTest(bool e)
qmlBindingsTest = qmlBindingsTestEnv();
}
+void QV4Compiler::enableV4(bool e)
+{
+ qmlEnableV4 = e;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qv4compiler_p.h b/src/declarative/qml/v4/qv4compiler_p.h
index 9fafaf95af..cb5225a9cf 100644
--- a/src/declarative/qml/v4/qv4compiler_p.h
+++ b/src/declarative/qml/v4/qv4compiler_p.h
@@ -92,6 +92,7 @@ public:
static void dump(const QByteArray &);
static void enableBindingsTest(bool);
+ static void enableV4(bool);
private:
QV4CompilerPrivate *d;
};
diff --git a/src/declarative/qml/v8/qv8contextwrapper.cpp b/src/declarative/qml/v8/qv8contextwrapper.cpp
index 29857b2585..46cf0e4298 100644
--- a/src/declarative/qml/v8/qv8contextwrapper.cpp
+++ b/src/declarative/qml/v8/qv8contextwrapper.cpp
@@ -317,21 +317,17 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
int propertyIdx = context->propertyNames->value(propertystring);
if (propertyIdx != -1) {
- typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
if (propertyIdx < context->idValueCount) {
- if (ep->captureProperties)
- ep->capturedProperties << CapturedProperty(&context->idValues[propertyIdx].bindings);
-
+ ep->captureProperty(&context->idValues[propertyIdx].bindings);
return engine->newQObject(context->idValues[propertyIdx]);
} else {
QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
- if (ep->captureProperties)
- ep->capturedProperties << CapturedProperty(context->asQDeclarativeContext(), -1,
- propertyIdx + cp->notifyIndex);
+ ep->captureProperty(context->asQDeclarativeContext(), -1,
+ propertyIdx + cp->notifyIndex);
const QVariant &value = cp->propertyValues.at(propertyIdx);
if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
index 40cb021512..eea455d332 100644
--- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
@@ -229,10 +229,8 @@ static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8
if (notify == 0x0FFF) notify = -1; \
\
QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \
- if (ep && notify /* 0 means constant */ && ep->captureProperties) { \
- typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
- ep->capturedProperties << CapturedProperty(object, index, notify); \
- } \
+ if (ep && notify /* 0 means constant */ ) \
+ ep->captureProperty(object, index, notify); \
\
cpptype value = defaultvalue; \
void *args[] = { &value, 0 }; \
@@ -255,10 +253,8 @@ static v8::Handle<v8::Value> name ## ValueGetterDirect(v8::Local<v8::String>, co
if (notify == 0x0FFF) notify = -1; \
\
QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \
- if (ep && notify /* 0 means constant */ && ep->captureProperties) { \
- typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
- ep->capturedProperties << CapturedProperty(object, index, notify); \
- } \
+ if (ep && notify /* 0 means constant */ ) \
+ ep->captureProperty(object, index, notify); \
\
cpptype value = defaultvalue; \
void *args[] = { &value, 0 }; \
@@ -508,8 +504,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
return v8::Handle<v8::Value>();
}
- typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
-
if (result->isFunction()) {
if (result->isVMEFunction()) {
return ((QDeclarativeVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex);
@@ -526,11 +520,11 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
}
QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0;
- if (ep && ep->captureProperties && !result->isConstant()) {
+ if (ep && !result->isConstant()) {
if (result->coreIndex == 0)
- ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
+ ep->captureProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
else
- ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
+ ep->captureProperty(object, result->coreIndex, result->notifyIndex);
}
if (result->isVMEProperty())
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml
new file mode 100644
index 0000000000..b5cc59e2c0
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyDeleteObject {
+ property int result: nestedObject.intProperty + deleteNestedObject
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml
new file mode 100644
index 0000000000..2b8b113c34
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: root
+ property int test: root.value
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
index 781b78663f..9213b61a3c 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
@@ -161,6 +161,7 @@ void registerTypes()
qmlRegisterExtendedType<DefaultPropertyExtendedObject, DefaultPropertyExtensionObject>("Qt.test", 1,0, "DefaultPropertyExtendedObject");
qmlRegisterType<OverrideDefaultPropertyObject>("Qt.test", 1,0, "OverrideDefaultPropertyObject");
qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass");
+ qmlRegisterType<MyDeleteObject>("Qt.test", 1,0, "MyDeleteObject");
qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass");
// test scarce resource property binding post-evaluation optimisation
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
index af4225c8da..9fbbd5052b 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
@@ -1229,6 +1229,26 @@ private:
QList<QPoint> m_pointList; // not a supported sequence type
};
+class MyDeleteObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *nestedObject READ nestedObject NOTIFY nestedObjectChanged);
+ Q_PROPERTY(int deleteNestedObject READ deleteNestedObject NOTIFY deleteNestedObjectChanged);
+
+public:
+ MyDeleteObject() : m_nestedObject(new MyQmlObject) {}
+
+ QObject *nestedObject() const { return m_nestedObject; }
+ int deleteNestedObject() { delete m_nestedObject; m_nestedObject = 0; return 1; }
+
+signals:
+ void nestedObjectChanged();
+ void deleteNestedObjectChanged();
+
+private:
+ MyQmlObject *m_nestedObject;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index ee228ec3b8..57e4fe1a46 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -51,6 +51,7 @@
#include <private/qdeclarativeengine_p.h>
#include <private/qv8gccallback_p.h>
#include <private/qdeclarativevmemetaobject_p.h>
+#include <private/qv4compiler_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
#include "../shared/util.h"
@@ -216,7 +217,8 @@ private slots:
void signalHandlers();
void doubleEvaluate();
void forInLoop();
-
+ void nonNotifyable();
+ void deleteWhileBindingRunning();
void callQtInvokables();
void invokableObjectArg();
void invokableObjectRet();
@@ -5046,6 +5048,39 @@ void tst_qdeclarativeecmascript::doubleEvaluate()
delete object;
}
+static QStringList messages;
+static void captureMsgHandler(QtMsgType, const char *msg)
+{
+ messages.append(QLatin1String(msg));
+}
+
+void tst_qdeclarativeecmascript::nonNotifyable()
+{
+ QV4Compiler::enableV4(false);
+ QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
+ QV4Compiler::enableV4(true);
+
+ QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
+ messages.clear();
+ QObject *object = component.create();
+ qInstallMsgHandler(old);
+
+ QVERIFY(object != 0);
+
+ QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
+ component.url().toString() +
+ QLatin1String(":5 depends on non-NOTIFYable properties:");
+ QString expected2 = QLatin1String(" ") +
+ QLatin1String(object->metaObject()->className()) +
+ QLatin1String("::value");
+
+ QCOMPARE(messages.length(), 2);
+ QCOMPARE(messages.at(0), expected1);
+ QCOMPARE(messages.at(1), expected2);
+
+ delete object;
+}
+
void tst_qdeclarativeecmascript::forInLoop()
{
QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
@@ -5065,6 +5100,15 @@ void tst_qdeclarativeecmascript::forInLoop()
delete object;
}
+// An object the binding depends on is deleted while the binding is still running
+void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
QTEST_MAIN(tst_qdeclarativeecmascript)
#include "tst_qdeclarativeecmascript.moc"