diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2012-04-11 14:56:22 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2012-04-11 16:05:03 +0200 |
commit | a896d4b39ec3d45ba708d9b36ea9c864b1df2136 (patch) | |
tree | 45cfe153cce6114c2c76c48dc0bdabde2a8cf3e3 /src/qml | |
parent | 24fb8dc27eddfdd62bd2c3a6e863cbf433762cd6 (diff) | |
parent | 65bfc35429e845cf6b76d58107360a1360a654fc (diff) |
Merge remote-tracking branch 'origin/master' into api_changes
Conflicts:
src/qml/debugger/qqmlprofilerservice_p.h
src/qml/qml/qqmlboundsignal.cpp
src/qml/qml/v4/qv4bindings.cpp
src/quick/items/qquickshadereffect.cpp
src/quick/particles/qquickcustomparticle.cpp
src/quick/qtquick2.cpp
Change-Id: Ia9c6517035ae912fa75e77473a452bd3383def56
Diffstat (limited to 'src/qml')
45 files changed, 997 insertions, 867 deletions
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp index 83b2192313..59bceaaf4e 100644 --- a/src/qml/animations/qanimationgroupjob.cpp +++ b/src/qml/animations/qanimationgroupjob.cpp @@ -51,8 +51,7 @@ QAnimationGroupJob::QAnimationGroupJob() QAnimationGroupJob::~QAnimationGroupJob() { - while (firstChild() != 0) - delete firstChild(); + clear(); } void QAnimationGroupJob::topLevelAnimationLoopChanged() @@ -123,9 +122,16 @@ void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation) void QAnimationGroupJob::clear() { - //### should this remove and delete, or just remove? - while (firstChild() != 0) - delete firstChild(); //removeAnimation(firstChild()); + QAbstractAnimationJob *child = firstChild(); + QAbstractAnimationJob *nextSibling = 0; + while (child != 0) { + child->m_group = 0; + nextSibling = child->nextSibling(); + delete child; + child = nextSibling; + } + m_firstChild = 0; + m_lastChild = 0; } void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime() diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index 318e0bd71f..115f3cbc3a 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -55,9 +55,9 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler }; // Execute code in constructor before first QQmlEngine is instantiated -#if defined(QT_DECLARATIVE_DEBUG_NO_WARNING) +#if defined(QT_QML_DEBUG_NO_WARNING) static QQmlDebuggingEnabler qmlEnableDebuggingHelper(false); -#elif defined(QT_DECLARATIVE_DEBUG) +#elif defined(QT_QML_DEBUG) || defined(QT_DECLARATIVE_DEBUG) static QQmlDebuggingEnabler qmlEnableDebuggingHelper(true); #endif diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp index dcf93b400e..468b653a1f 100644 --- a/src/qml/debugger/qqmldebugserver.cpp +++ b/src/qml/debugger/qqmldebugserver.cpp @@ -255,7 +255,7 @@ QQmlDebugServer *QQmlDebugServer::instance() commandLineTested = true; QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); -#ifndef QQML_NO_DEBUG_PROTOCOL +#ifndef QT_QML_NO_DEBUGGER // ### remove port definition when protocol is changed int port = 0; bool block = false; @@ -398,7 +398,6 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message) iter.value()->stateChanged(newState); } - qDebug("QML Debugger: Connection established."); d->messageArrivedCondition.wakeAll(); } else if (op == 1) { @@ -458,14 +457,14 @@ void QQmlDebugServerPrivate::_q_sendMessages(const QList<QByteArray> &messages) QList<QQmlDebugService*> QQmlDebugServer::services() const { - const Q_D(QQmlDebugServer); + Q_D(const QQmlDebugServer); QReadLocker(&d->pluginsLock); return d->plugins.values(); } QStringList QQmlDebugServer::serviceNames() const { - const Q_D(QQmlDebugServer); + Q_D(const QQmlDebugServer); QReadLocker(&d->pluginsLock); return d->plugins.keys(); } diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp index cd09b69e48..d8997fd587 100644 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ b/src/qml/debugger/qqmlenginedebugservice.cpp @@ -67,7 +67,7 @@ QQmlEngineDebugService *QQmlEngineDebugService::instance() } QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent) - : QQmlDebugService(QStringLiteral("QmlDebugger"), 1, parent), + : QQmlDebugService(QStringLiteral("QmlDebugger"), 2, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(0) { @@ -86,7 +86,8 @@ QDataStream &operator<<(QDataStream &ds, const QQmlEngineDebugService::QQmlObjectData &data) { ds << data.url << data.lineNumber << data.columnNumber << data.idString - << data.objectName << data.objectType << data.objectId << data.contextId; + << data.objectName << data.objectType << data.objectId << data.contextId + << data.parentId; return ds; } @@ -94,7 +95,8 @@ QDataStream &operator>>(QDataStream &ds, QQmlEngineDebugService::QQmlObjectData &data) { ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString - >> data.objectName >> data.objectType >> data.objectId >> data.contextId; + >> data.objectName >> data.objectType >> data.objectId >> data.contextId + >> data.parentId; return ds; } @@ -264,7 +266,7 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message, QQmlObjectProperty prop; prop.type = QQmlObjectProperty::SignalProperty; prop.hasNotifySignal = false; - QQmlExpression *expr = signalHandler->expression(); + QQmlBoundSignalExpression *expr = signalHandler->expression(); if (expr) { prop.value = expr->expression(); QObject *scope = expr->scopeObject(); @@ -376,7 +378,7 @@ QQmlEngineDebugService::objectData(QObject *object) rv.objectName = object->objectName(); rv.objectId = QQmlDebugService::idForObject(object); rv.contextId = QQmlDebugService::idForObject(qmlContext(object)); - + rv.parentId = QQmlDebugService::idForObject(object->parent()); QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); if (type) { QString typeName = type->qmlTypeName(); @@ -603,9 +605,9 @@ bool QQmlEngineDebugService::setBinding(int objectId, if (isLiteralValue) { property.write(expression); } else if (hasValidSignal(object, propertyName)) { - QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString()); + QQmlBoundSignalExpression *qmlExpression = new QQmlBoundSignalExpression(QQmlContextData::get(context), object, expression.toString(), + false, filename, line, column); QQmlPropertyPrivate::setSignalExpression(property, qmlExpression); - qmlExpression->setSourceLocation(filename, line, column); } else if (property.isProperty()) { QQmlBinding *binding = new QQmlBinding(expression.toString(), false, object, QQmlContextData::get(context), filename, line, column);; binding->setTarget(property); diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h index 19a5776e27..3b855cb602 100644 --- a/src/qml/debugger/qqmlenginedebugservice_p.h +++ b/src/qml/debugger/qqmlenginedebugservice_p.h @@ -83,6 +83,7 @@ public: QString objectType; int objectId; int contextId; + int parentId; }; struct QQmlObjectProperty { diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index c643073308..7109286197 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -195,7 +195,7 @@ void QQmlProfilerService::rangeData(RangeType range, const QUrl &rData) if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled) return; - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1, -1, 0, 0}; + QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(), -1, -1, 0, 0}; processMessage(rd); } @@ -213,7 +213,7 @@ void QQmlProfilerService::rangeLocation(RangeType range, const QUrl &fileName, i if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled) return; - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line, column, 0, 0}; + QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(), line, column, 0, 0}; processMessage(rd); } diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 2e351792cc..8662abb52e 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -54,7 +54,7 @@ // #include <private/qqmldebugservice_p.h> -#include "qqmlexpression.h" +#include <private/qqmlboundsignal_p.h> #include <QtCore/qelapsedtimer.h> #include <QtCore/qmetaobject.h> @@ -201,20 +201,20 @@ struct QQmlBindingProfiler { }; struct QQmlHandlingSignalProfiler { - QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlExpression *expression) + QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlBoundSignalExpression *expression) { enabled = QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false; - if (enabled) - init(signal, expression); - } - - QQmlHandlingSignalProfiler(QObject *object, int index, QQmlExpression *expression) - { - enabled = QQmlProfilerService::instance - ? QQmlProfilerService::instance->profilingEnabled() : false; - if (enabled) - init(object->metaObject()->method(index), expression); + if (enabled) { + QQmlProfilerService *service = QQmlProfilerService::instance; + service->startRange(QQmlProfilerService::HandlingSignal); + service->rangeData(QQmlProfilerService::HandlingSignal, + QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ") + + expression->expression()); + service->rangeLocation(QQmlProfilerService::HandlingSignal, + expression->sourceFile(), expression->lineNumber(), + expression->columnNumber()); + } } ~QQmlHandlingSignalProfiler() @@ -224,19 +224,6 @@ struct QQmlHandlingSignalProfiler { } bool enabled; - -private: - void init(const QMetaMethod &signal, QQmlExpression *expression) - { - QQmlProfilerService *service = QQmlProfilerService::instance; - service->startRange(QQmlProfilerService::HandlingSignal); - service->rangeData(QQmlProfilerService::HandlingSignal, - QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ") - + expression->expression()); - service->rangeLocation(QQmlProfilerService::HandlingSignal, - expression->sourceFile(), expression->lineNumber(), - expression->columnNumber()); - } }; struct QQmlObjectCreatingProfiler { diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h index fe2ee1762b..1d5ecac08e 100644 --- a/src/qml/qml/qqmlabstractexpression_p.h +++ b/src/qml/qml/qqmlabstractexpression_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE -class QQmlAbstractExpression +class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression { public: QQmlAbstractExpression(); diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h index 8e67a58511..7558ab3e35 100644 --- a/src/qml/qml/qqmlaccessors_p.h +++ b/src/qml/qml/qqmlaccessors_p.h @@ -47,7 +47,7 @@ #include <QtCore/qhash.h> #include <QtCore/QReadWriteLock> -#ifdef Q_OS_QNX +#if defined(Q_OS_QNX) || defined(Q_OS_LINUX) #include <stdint.h> #endif diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 3a3bf403e6..b77484c7e5 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -49,6 +49,7 @@ #include "qqml.h" #include "qqmlcontext.h" #include "qqmlglobal_p.h" +#include "qqmlrewrite_p.h" #include <private/qqmlprofilerservice_p.h> #include <private/qv8debugservice_p.h> @@ -59,6 +60,105 @@ Q_DECLARE_METATYPE(QJSValue) QT_BEGIN_NAMESPACE +static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { + QQmlBoundSignalExpression::expressionIdentifier, + QQmlBoundSignalExpression::expressionChanged +}; + +QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression, + bool isRewritten, const QString &fileName, int line, int column) + : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable) +{ + setNotifyOnValueChanged(false); + setContext(ctxt); + setScopeObject(scope); + m_expression = QString::fromUtf8(expression); + m_expressionFunctionValid = false; + m_expressionFunctionRewritten = isRewritten; + m_fileName = fileName; + m_line = line; + m_column = column; +} + +QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression, + bool isRewritten, const QString &fileName, int line, int column) + : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable) +{ + setNotifyOnValueChanged(false); + setContext(ctxt); + setScopeObject(scope); + m_expression = expression; + m_expressionFunctionValid = false; + m_expressionFunctionRewritten = isRewritten; + m_fileName = fileName; + m_line = line; + m_column = column; +} + +QQmlBoundSignalExpression::~QQmlBoundSignalExpression() +{ + qPersistentDispose(m_v8function); + qPersistentDispose(m_v8qmlscope); +} + +QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e) +{ + QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e); + return QLatin1String("\"") + This->m_expression + QLatin1String("\""); +} + +void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *) +{ + // bound signals do not notify on change. +} + +// This mirrors code in QQmlExpressionPrivate::value() and v8value(). +// Any change made here should be made there and vice versa. +void QQmlBoundSignalExpression::evaluate(QObject *secondaryScope) +{ + Q_ASSERT (context() && engine()); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); + + ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. + { + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(ep->v8engine()->context()); + if (!m_expressionFunctionValid) { + bool ok = true; + QString code; + if (m_expressionFunctionRewritten) { + code = m_expression; + } else { + QQmlRewrite::RewriteSignalHandler rewriteSignalHandler; + code = rewriteSignalHandler(m_expression, m_functionName, &ok); + } + + if (ok) + m_v8function = evalFunction(context(), scopeObject(), code, m_fileName, m_line, &m_v8qmlscope); + + if (m_v8function.IsEmpty() || m_v8function->IsNull()) { + ep->dereferenceScarceResources(); + return; // could not evaluate function. Not valid. + } + + setUseSharedContext(false); + m_expressionFunctionValid = true; + } + + if (secondaryScope) { + QObject *restoreSecondaryScope = 0; + restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, secondaryScope); + QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0); + ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, restoreSecondaryScope); + } else { + QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0); + } + } + ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. +} + +//////////////////////////////////////////////////////////////////////// + class QQmlBoundSignalParameters : public QObject { Q_OBJECT @@ -104,10 +204,9 @@ QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal() } } -void QQmlAbstractBoundSignal::addToObject() +void QQmlAbstractBoundSignal::addToObject(QObject *obj) { Q_ASSERT(!m_prevSignal); - QObject *obj = object(); Q_ASSERT(obj); QQmlData *data = QQmlData::get(obj, true); @@ -120,13 +219,15 @@ void QQmlAbstractBoundSignal::addToObject() QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *owner) -: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0), m_owner(owner) +: m_expression(0), m_params(0), m_scope(scope), m_signal(signal), m_paramsValid(false), m_isEvaluating(false) { // This is thread safe. Although it may be updated by two threads, they // will both set it to the same value - so the worst thing that can happen // is that they both do the work to figure it out. Boo hoo. if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + addToObject(owner); + QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); } @@ -144,7 +245,7 @@ int QQmlBoundSignal::index() const /*! Returns the signal expression. */ -QQmlExpression *QQmlBoundSignal::expression() const +QQmlBoundSignalExpression *QQmlBoundSignal::expression() const { return m_expression; } @@ -156,9 +257,9 @@ QQmlExpression *QQmlBoundSignal::expression() const The QQmlBoundSignal instance takes ownership of \a e. The caller is assumes ownership of the returned QQmlExpression. */ -QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e) +QQmlBoundSignalExpression *QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e) { - QQmlExpression *rv = m_expression; + QQmlBoundSignalExpression *rv = m_expression; m_expression = e; if (m_expression) m_expression->setNotifyOnValueChanged(false); return rv; @@ -183,8 +284,8 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) } if (m_params) m_params->setValues(a); - if (m_expression && m_expression->engine()) { - QQmlExpressionPrivate::get(m_expression)->value(m_params); + if (m_expression && m_expression->context() && m_expression->engine()) { + m_expression->evaluate(m_params); if (m_expression && m_expression->hasError()) QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error()); } @@ -247,7 +348,7 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, if (scope == "Qt") meta = &QObject::staticQtMetaObject; else - meta = static_cast<QQmlBoundSignal*>(parent)->object()->metaObject(); + meta = static_cast<QQmlBoundSignal*>(parent)->scope()->metaObject(); for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { QMetaEnum m = meta->enumerator(i); if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) { @@ -300,71 +401,6 @@ int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) } } -//////////////////////////////////////////////////////////////////////// - -QQmlBoundSignalNoParams::QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal, - QObject *owner) -: m_expression(0), m_owner(owner), m_index(signal.methodIndex()), m_isEvaluating(false) -{ - callback = &subscriptionCallback; - QQmlNotifierEndpoint::connect(scope, m_index); -} - -QQmlBoundSignalNoParams::~QQmlBoundSignalNoParams() -{ - delete m_expression; - m_expression = 0; -} - -int QQmlBoundSignalNoParams::index() const -{ - return m_index; -} - -/*! - Returns the signal expression. -*/ -QQmlExpression *QQmlBoundSignalNoParams::expression() const -{ - return m_expression; -} - -/*! - Sets the signal expression to \a e. Returns the current signal expression, - or null if there is no signal expression. - - The QQmlBoundSignalNoParams instance takes ownership of \a e. The caller is - assumes ownership of the returned QQmlExpression. -*/ -QQmlExpression *QQmlBoundSignalNoParams::setExpression(QQmlExpression *e) -{ - QQmlExpression *rv = m_expression; - m_expression = e; - if (m_expression) m_expression->setNotifyOnValueChanged(false); - return rv; -} - -void QQmlBoundSignalNoParams::subscriptionCallback(QQmlNotifierEndpoint *e) -{ - QQmlBoundSignalNoParams *s = static_cast<QQmlBoundSignalNoParams*>(e); - if (!s->m_expression) - return; - - if (QQmlDebugService::isDebuggingEnabled()) - QV8DebugService::instance()->signalEmitted(QString::fromAscii(s->m_owner->metaObject()->method(s->m_index).methodSignature())); - - QQmlHandlingSignalProfiler prof(s->m_owner, s->m_index, s->m_expression); - - s->m_isEvaluating = true; - - if (s->m_expression && s->m_expression->engine()) { - QQmlExpressionPrivate::get(s->m_expression)->value(); - if (s->m_expression && s->m_expression->hasError()) - QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error()); - } - s->m_isEvaluating = false; -} - QT_END_NAMESPACE #include <qqmlboundsignal.moc> diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 5fc8c3522f..c6ce875d07 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -53,15 +53,51 @@ // We mean it. // -#include "qqmlexpression.h" - #include <QtCore/qmetaobject.h> -#include <private/qqmlnotifier_p.h> +#include <private/qqmlabstractexpression_p.h> +#include <private/qqmljavascriptexpression_p.h> #include <private/qobject_p.h> QT_BEGIN_NAMESPACE +class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression +{ +public: + QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression, + bool isRewritten, const QString &fileName, int line, int column); + QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression, + bool isRewritten, const QString &fileName, int line, int column); + ~QQmlBoundSignalExpression(); + + // "inherited" from QQmlJavaScriptExpression. + static QString expressionIdentifier(QQmlJavaScriptExpression *); + static void expressionChanged(QQmlJavaScriptExpression *); + + // evaluation of a bound signal expression doesn't return any value + void evaluate(QObject *secondaryScope = 0); + + QString sourceFile() const { return m_fileName; } + int lineNumber() const { return m_line; } + int columnNumber() const { return m_column; } + QString expression() const { return m_expression; } + + QQmlEngine *engine() const { return context() ? context()->engine : 0; } + +private: + v8::Persistent<v8::Object> m_v8qmlscope; + v8::Persistent<v8::Function> m_v8function; + + QString m_expression; + QString m_functionName; // hint for debugger + QString m_fileName; + int m_line; + int m_column; + + bool m_expressionFunctionValid:1; + bool m_expressionFunctionRewritten:1; +}; + class Q_QML_EXPORT QQmlAbstractBoundSignal { public: @@ -69,11 +105,12 @@ public: virtual ~QQmlAbstractBoundSignal(); virtual int index() const = 0; - virtual QQmlExpression *expression() const = 0; - virtual QQmlExpression *setExpression(QQmlExpression *) = 0; - virtual QObject *object() = 0; + virtual QQmlBoundSignalExpression *expression() const = 0; + virtual QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *) = 0; + virtual QObject *scope() = 0; - void addToObject(); +protected: + void addToObject(QObject *owner); private: friend class QQmlData; @@ -93,9 +130,9 @@ public: int index() const; - QQmlExpression *expression() const; - QQmlExpression *setExpression(QQmlExpression *); - QObject *object() { return m_owner; } + QQmlBoundSignalExpression *expression() const; + QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *); + QObject *scope() { return m_scope; } bool isEvaluating() const { return m_isEvaluating; } @@ -103,39 +140,14 @@ protected: virtual int qt_metacall(QMetaObject::Call c, int id, void **a); private: - QQmlExpression *m_expression; + QQmlBoundSignalExpression *m_expression; + QQmlBoundSignalParameters *m_params; + QObject *m_scope; QMetaMethod m_signal; bool m_paramsValid : 1; bool m_isEvaluating : 1; - QQmlBoundSignalParameters *m_params; - QObject *m_owner; -}; - -class Q_QML_EXPORT QQmlBoundSignalNoParams : public QQmlAbstractBoundSignal, - public QQmlNotifierEndpoint -{ -public: - QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal, QObject *owner); - virtual ~QQmlBoundSignalNoParams(); - - int index() const; - - QQmlExpression *expression() const; - QQmlExpression *setExpression(QQmlExpression *); - QObject *object() { return m_owner; } - - static void subscriptionCallback(QQmlNotifierEndpoint *e); - - bool isEvaluating() const { return m_isEvaluating; } - -private: - QQmlExpression *m_expression; - QObject *m_owner; - int m_index; - bool m_isEvaluating; }; - QT_END_NAMESPACE #endif // QQMLBOUNDSIGNAL_P_H diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index dec9911481..54577f9b92 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -3468,6 +3468,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding, store.value = js.compiledIndex; store.context = js.bindingContext.stack; store.owner = js.bindingContext.owner; + store.isAlias = prop->isAlias; if (valueTypeProperty) { store.isRoot = (compileState->root == valueTypeProperty->parent); } else { @@ -3488,30 +3489,29 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding, } else if (ref.dataType == BindingReference::QtScript) { const JSBindingReference &js = static_cast<const JSBindingReference &>(ref); - QQmlInstruction store; - store.assignBinding.value = output->indexForString(js.rewrittenExpression); - store.assignBinding.context = js.bindingContext.stack; - store.assignBinding.owner = js.bindingContext.owner; - store.assignBinding.line = binding->location.start.line; - store.assignBinding.column = binding->location.start.column; + Instruction::StoreBinding store; + store.value = output->indexForString(js.rewrittenExpression); + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; + store.line = binding->location.start.line; + store.column = binding->location.start.column; + store.isAlias = prop->isAlias; if (valueTypeProperty) { - store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent); + store.isRoot = (compileState->root == valueTypeProperty->parent); } else { - store.assignBinding.isRoot = (compileState->root == obj); + store.isRoot = (compileState->root == obj); } Q_ASSERT(js.bindingContext.owner == 0 || (js.bindingContext.owner != 0 && valueTypeProperty)); if (js.bindingContext.owner) { - store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + store.property = genValueTypeData(prop, valueTypeProperty); } else { - store.assignBinding.property = prop->core; + store.property = prop->core; } - output->addInstructionHelper( - !prop->isAlias ? QQmlInstruction::StoreBinding - : QQmlInstruction::StoreBindingOnAlias - , store); + + output->addInstruction(store); } else { Q_ASSERT(!"Unhandled BindingReference::DataType type"); } @@ -3588,8 +3588,7 @@ bool QQmlCompiler::completeComponentBuild() bool isSharable = false; binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); - if (isSharable && !binding.property->isAlias /* See above re alias */ && - binding.property->type != qMetaTypeId<QQmlBinding*>()) { + if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) { binding.dataType = BindingReference::V8; sharedBindings.append(b); diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 7bddaadcd0..2e46192246 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1396,7 +1396,8 @@ void QV8IncubatorResource::statusChanged(Status s) { if (s == Ready) { Q_ASSERT(QQmlData::get(object())); - QQmlData::get(object())->setImplicitDestructible(); + QQmlData::get(object())->explicitIndestructibleSet = false; + QQmlData::get(object())->indestructible = false; } if (!me.IsEmpty()) { // Will be false in synchronous mode diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index e7e001c4f2..3dd1c3ccba 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -181,11 +181,25 @@ public: QQmlNotifier *objectNameNotifier() const; QHash<int, QObject *> *attachedProperties() const; + static inline bool wasDeleted(QObject *); private: // For objectNameNotifier and attachedProperties mutable QQmlDataExtended *extendedData; }; +bool QQmlData::wasDeleted(QObject *object) +{ + if (!object) + return true; + + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + if (priv->wasDeleted) + return true; + + return priv->declarativeData && + static_cast<QQmlData *>(priv->declarativeData)->isQueuedForDeletion; +} + QQmlNotifierEndpoint *QQmlData::notify(int index) { Q_ASSERT(index <= 0xFFFF); diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index df5f7f8ee9..82289311c9 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -297,16 +297,16 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component) { - return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName) - .arg(component.majorVersion) - .arg(component.minorVersion)); + const QString output = QString::fromLatin1("{%1 %2.%3}"). + arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion); + return debug << qPrintable(output); } QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script) { - return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace) - .arg(script.majorVersion) - .arg(script.minorVersion)); + const QString output = QString::fromLatin1("{%1 %2.%3}"). + arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion); + return debug << qPrintable(output); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 955c8ce414..153d6b325a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -598,9 +598,17 @@ QQmlEngine::~QQmlEngine() /*! Clears the engine's internal component cache. - Normally the QQmlEngine caches components loaded from qml - files. This method clears this cache and forces the component to be - reloaded. + This function causes the property metadata of all components previously + loaded by the engine to be destroyed. All previously loaded components and + the property bindings for all extant objects created from those components will + cease to function. + + This function returns the engine to a state where it does not contain any loaded + component data. This may be useful in order to reload a smaller subset of the + previous component set, or to load a new version of a previously loaded component. + + Once the component cache has been cleared, components must be loaded before + any new objects can be created. */ void QQmlEngine::clearComponentCache() { diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index d760486605..940b3c8354 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -60,7 +60,7 @@ static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = { QQmlExpressionPrivate::QQmlExpressionPrivate() : QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable), expressionFunctionValid(true), expressionFunctionRewritten(false), - extractExpressionFromFunction(false), line(-1), dataRef(0) + line(-1) { } @@ -68,8 +68,6 @@ QQmlExpressionPrivate::~QQmlExpressionPrivate() { qPersistentDispose(v8qmlscope); qPersistentDispose(v8function); - if (dataRef) dataRef->release(); - dataRef = 0; } void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me) @@ -321,13 +319,7 @@ QQmlContext *QQmlExpression::context() const QString QQmlExpression::expression() const { Q_D(const QQmlExpression); - if (d->extractExpressionFromFunction && context()->engine()) { - QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(context()->engine()); - v8::HandleScope handle_scope; - v8::Context::Scope scope(v8engine->context()); - - return v8engine->toString(v8::Handle<v8::Value>(d->v8function)); - } else if (!d->expressionUtf8.isEmpty()) { + if (!d->expressionUtf8.isEmpty()) { return QString::fromUtf8(d->expressionUtf8); } else { return d->expression; @@ -351,7 +343,7 @@ void QQmlExpression::setExpression(const QString &expression) } // Must be called with a valid handle scope -v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined) +v8::Local<v8::Value> QQmlExpressionPrivate::v8value(bool *isUndefined) { if (!expressionFunctionValid) { bool ok = true; @@ -369,21 +361,10 @@ v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, boo expressionFunctionValid = true; } - - if (secondaryScope) { - v8::Local<v8::Value> result; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QObject *restoreSecondaryScope = 0; - restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); - result = evaluate(context(), v8function, isUndefined); - ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); - return result; - } else { - return evaluate(context(), v8function, isUndefined); - } + return evaluate(context(), v8function, isUndefined); } -QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) +QVariant QQmlExpressionPrivate::value(bool *isUndefined) { Q_Q(QQmlExpression); @@ -400,7 +381,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined { v8::HandleScope handle_scope; v8::Context::Scope context_scope(ep->v8engine()->context()); - v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined); + v8::Local<v8::Value> result = v8value(isUndefined); rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >()); } @@ -421,7 +402,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined QVariant QQmlExpression::evaluate(bool *valueIsUndefined) { Q_D(QQmlExpression); - return d->value(0, valueIsUndefined); + return d->value(valueIsUndefined); } /*! diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index 186e3aebf9..d32e2d314c 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -82,9 +82,9 @@ public: void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, int, int); void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, int, int); - QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); + QVariant value(bool *isUndefined = 0); - v8::Local<v8::Value> v8value(QObject *secondaryScope = 0, bool *isUndefined = 0); + v8::Local<v8::Value> v8value(bool *isUndefined = 0); static inline QQmlExpressionPrivate *get(QQmlExpression *expr); static inline QQmlExpression *get(QQmlExpressionPrivate *expr); @@ -96,7 +96,6 @@ public: bool expressionFunctionValid:1; bool expressionFunctionRewritten:1; - bool extractExpressionFromFunction:1; // "Inherited" from QQmlJavaScriptExpression static QString expressionIdentifier(QQmlJavaScriptExpression *); @@ -113,8 +112,6 @@ public: int line; int column; QString name; //function name, hint for the debugger - - QQmlRefCount *dataRef; }; QQmlExpressionPrivate *QQmlExpressionPrivate::get(QQmlExpression *expr) diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 1224efdaac..be870cad4c 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -545,27 +545,27 @@ QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork } } - // TODO: Should this search be omitted if found == true? - - // step 2: search for extension with encoded version major - foreach (const QString &p, database->fileImportPath) { - dir = p+Slash+url; + if (!found) { + // step 2: search for extension with encoded version major + foreach (const QString &p, database->fileImportPath) { + dir = p+Slash+url; - QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir")); - const QString absoluteFilePath = fi.absoluteFilePath(); + QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir")); + const QString absoluteFilePath = fi.absoluteFilePath(); - if (fi.isFile()) { - found = true; + if (fi.isFile()) { + found = true; - const QString absolutePath = fi.absolutePath(); - if (absolutePath.at(0) == QLatin1Char(':')) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(fi.absolutePath()).toString(); - uri = resolvedUri(dir, database); - if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return QString(); - break; + const QString absolutePath = fi.absolutePath(); + if (absolutePath.at(0) == QLatin1Char(':')) + url = QLatin1String("qrc://") + absolutePath.mid(1); + else + url = QUrl::fromLocalFile(fi.absolutePath()).toString(); + uri = resolvedUri(dir, database); + if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) + return QString(); + break; + } } } diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp index b37117e69b..82cf235712 100644 --- a/src/qml/qml/qqmlinstruction.cpp +++ b/src/qml/qml/qqmlinstruction.cpp @@ -210,9 +210,6 @@ void QQmlCompiledData::dump(QQmlInstruction *instr, int idx) case QQmlInstruction::StoreBinding: qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; break; - case QQmlInstruction::StoreBindingOnAlias: - qWarning().nospace() << idx << "\t\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; - break; case QQmlInstruction::StoreV4Binding: qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignV4Binding.property << "\t" << instr->assignV4Binding.value << "\t" << instr->assignV4Binding.context; break; diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index b7533aca68..cfc530df04 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -114,7 +114,6 @@ QT_BEGIN_NAMESPACE F(BeginObject, begin) \ F(InitV8Bindings, initV8Bindings) \ F(StoreBinding, assignBinding) \ - F(StoreBindingOnAlias, assignBinding) \ F(StoreV8Binding, assignBinding) \ F(StoreV4Binding, assignV4Binding) \ F(StoreValueSource, assignValueSource) \ @@ -251,6 +250,7 @@ union QQmlInstruction short context; short owner; bool isRoot; + bool isAlias; ushort line; ushort column; }; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index f68c345f3a..075c1f6c4f 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -920,7 +920,7 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu Returns the expression associated with this signal property, or 0 if no signal expression exists. */ -QQmlExpression * +QQmlBoundSignalExpression * QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) { if (!(that.type() & QQmlProperty::SignalProperty)) @@ -948,9 +948,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that) Ownership of \a expr transfers to QML. Ownership of the return value is assumed by the caller. */ -QQmlExpression * +QQmlBoundSignalExpression * QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, - QQmlExpression *expr) + QQmlBoundSignalExpression *expr) { if (!(that.type() & QQmlProperty::SignalProperty)) { delete expr; @@ -970,13 +970,8 @@ QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that, return signalHandler->setExpression(expr); if (expr) { - QQmlAbstractBoundSignal *signal = 0; - if (that.method().parameterTypes().count()) - signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object); - else - signal = new QQmlBoundSignalNoParams(that.d->object, that.method(), that.d->object); - QQmlExpression *oldExpr = signal->setExpression(expr); - signal->addToObject(); + QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object); + QQmlBoundSignalExpression *oldExpr = signal->setExpression(expr); return oldExpr; } else { return 0; @@ -1531,13 +1526,29 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, return true; const char *valueType = 0; - if (value.userType() == QVariant::Invalid) valueType = "null"; - else valueType = QMetaType::typeName(value.userType()); + const char *propertyType = 0; + + if (value.userType() == QMetaType::QObjectStar) { + if (QObject *o = *(QObject **)value.constData()) { + valueType = o->metaObject()->className(); + + if (const QMetaObject *propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type)) { + propertyType = propertyMetaObject->className(); + } + } + } else if (value.userType() != QVariant::Invalid) { + valueType = QMetaType::typeName(value.userType()); + } + + if (!valueType) + valueType = "null"; + if (!propertyType) + propertyType = QMetaType::typeName(type); expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") + QLatin1String(valueType) + QLatin1String(" to ") + - QLatin1String(QMetaType::typeName(type))); + QLatin1String(propertyType)); return false; } diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index f4a9ced53b..e33c95ae41 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE class QQmlContext; -class QQmlExpression; +class QQmlBoundSignalExpression; class QQmlEnginePrivate; class QQmlJavaScriptExpression; class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount @@ -140,9 +140,9 @@ public: static QQmlAbstractBinding *setBinding(const QQmlProperty &that, QQmlAbstractBinding *, WriteFlags flags = DontRemoveBinding); - static QQmlExpression *signalExpression(const QQmlProperty &that); - static QQmlExpression *setSignalExpression(const QQmlProperty &that, - QQmlExpression *) ; + static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that); + static QQmlBoundSignalExpression *setSignalExpression(const QQmlProperty &that, + QQmlBoundSignalExpression *) ; static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); static bool writeBinding(QObject *, const QQmlPropertyData &, QQmlContextData *context, diff --git a/src/qml/qml/qqmlrewrite.cpp b/src/qml/qml/qqmlrewrite.cpp index 72bd23955b..bbb17b631d 100644 --- a/src/qml/qml/qqmlrewrite.cpp +++ b/src/qml/qml/qqmlrewrite.cpp @@ -51,6 +51,8 @@ DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP); namespace QQmlRewrite { +QString SharedBindingTester::evalString("eval"); + static void rewriteStringLiteral(AST::StringLiteral *ast, const QString *code, int startPosition, TextWriter *writer) { const unsigned position = ast->firstSourceLocation().begin() - startPosition + 1; @@ -419,6 +421,21 @@ QString RewriteSignalHandler::operator()(QQmlJS::AST::Node *node, const QString return rewritten; } +QString RewriteSignalHandler::operator()(const QString &code, const QString &name, bool *ok) +{ + Engine engine; + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) { + if (ok) *ok = false; + return QString(); + } + if (ok) *ok = true; + return operator()(parser.statement(), code, name); +} + } // namespace QQmlRewrite QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlrewrite_p.h b/src/qml/qml/qqmlrewrite_p.h index 1d69839878..efa10ce316 100644 --- a/src/qml/qml/qqmlrewrite_p.h +++ b/src/qml/qml/qqmlrewrite_p.h @@ -70,9 +70,11 @@ public: bool isSharable(const QString &code); bool isSharable(AST::Node *Node); - virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; } - virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; } - virtual bool visit(AST::CallExpression *) { _sharable = false; return false; } + inline virtual bool visit(AST::FunctionDeclaration *); + inline virtual bool visit(AST::FunctionExpression *); + inline virtual bool visit(AST::IdentifierExpression *); + + static QString evalString; }; class RewriteBinding: protected AST::Visitor @@ -133,6 +135,7 @@ class RewriteSignalHandler: protected AST::Visitor public: RewriteSignalHandler(); QString operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name); + QString operator()(const QString &code, const QString &name, bool *ok = 0); protected: void rewriteMultilineStrings(QString &code); @@ -142,6 +145,26 @@ protected: virtual bool visit(AST::StringLiteral *ast); }; +bool SharedBindingTester::visit(AST::FunctionDeclaration *) +{ + _sharable = false; + return false; +} + +bool SharedBindingTester::visit(AST::FunctionExpression *) +{ + _sharable = false; + return false; +} + +bool SharedBindingTester::visit(AST::IdentifierExpression *e) +{ + if (e->name == evalString) + _sharable = false; + + return false; // IdentifierExpression is a leaf node anyway +} + } // namespace QQmlRewrite QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index e1925eb238..37c0fb44a4 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -66,6 +66,11 @@ QQmlScript::Object::Object() : type(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1), componentCompileState(0), nextAliasingObject(0), nextIdObject(0) { + // initialize the members in the meta object + extObject.d.superdata = 0; + extObject.d.stringdata = 0; + extObject.d.data = 0; + extObject.d.extradata = 0; } QQmlScript::Object::~Object() diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 5412315d31..985d291a8e 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -204,13 +204,19 @@ inline bool fastHasBinding(QObject *o, int index) { QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData); + index &= 0xFFFFFF; // To handle value types + return ddata && (ddata->bindingBitsSize > index) && (ddata->bindingBits[index / 32] & (1 << (index % 32))); } static void removeBindingOnProperty(QObject *o, int index) { - QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, index, -1, 0); + int coreIndex = index & 0xFFFFFF; + int valueTypeIndex = index & 0xFF000000; + if (!valueTypeIndex) valueTypeIndex = -1; + + QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0); if (binding) binding->destroy(); } @@ -724,15 +730,10 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QMetaMethod signal = target->metaObject()->method(instr.signalIndex); - QQmlAbstractBoundSignal *bs = 0; - if (signal.parameterTypes().count()) - bs = new QQmlBoundSignal(target, signal, target); - else - bs = new QQmlBoundSignalNoParams(target, signal, target); - QQmlExpression *expr = - new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate); + QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target); + QQmlBoundSignalExpression *expr = + new QQmlBoundSignalExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column); bs->setExpression(expr); - bs->addToObject(); QML_END_INSTR(StoreSignal) QML_BEGIN_INSTR(StoreImportedScript) @@ -788,35 +789,23 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, bind->m_mePtr = &bindValues.top(); bind->setTarget(target, instr.property, CTXT); - typedef QQmlPropertyPrivate QDPP; - Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property)); - Q_ASSERT(bind->object() == target); - - bind->addToObject(); - QML_END_INSTR(StoreBinding) - - QML_BEGIN_INSTR(StoreBindingOnAlias) - QObject *target = - objects.at(objects.count() - 1 - instr.owner); - QObject *context = - objects.at(objects.count() - 1 - instr.context); + if (instr.isAlias) { + QQmlAbstractBinding *old = + QQmlPropertyPrivate::setBindingNoEnable(target, + instr.property.coreIndex, + instr.property.getValueTypeCoreIndex(), + bind); + if (old) { old->destroy(); } + } else { + typedef QQmlPropertyPrivate QDPP; + Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property)); + Q_ASSERT(bind->object() == target); - if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex)) - QML_NEXT_INSTR(StoreBindingOnAlias); + CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property)); - QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true, - context, CTXT, COMP->name, instr.line, - instr.column); - bindValues.push(bind); - bind->m_mePtr = &bindValues.top(); - bind->setTarget(target, instr.property, CTXT); - - QQmlAbstractBinding *old = - QQmlPropertyPrivate::setBindingNoEnable(target, instr.property.coreIndex, - instr.property.getValueTypeCoreIndex(), - bind); - if (old) { old->destroy(); } - QML_END_INSTR(StoreBindingOnAlias) + bind->addToObject(); + } + QML_END_INSTR(StoreBinding) QML_BEGIN_INSTR(StoreV4Binding) QObject *target = @@ -837,6 +826,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, Q_ASSERT(binding->propertyIndex() == (property & 0xFF00FFFF)); Q_ASSERT(binding->object() == target); + CLEAN_PROPERTY(target, property & 0xFF00FFFF); + binding->addToObject(); QML_END_INSTR(StoreV4Binding) @@ -855,11 +846,22 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, bindValues.push(binding); binding->m_mePtr = &bindValues.top(); - typedef QQmlPropertyPrivate QDPP; - Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property)); - Q_ASSERT(binding->object() == target); + if (instr.isAlias) { + QQmlAbstractBinding *old = + QQmlPropertyPrivate::setBindingNoEnable(target, + instr.property.coreIndex, + instr.property.getValueTypeCoreIndex(), + binding); + if (old) { old->destroy(); } + } else { + typedef QQmlPropertyPrivate QDPP; + Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property)); + Q_ASSERT(binding->object() == target); + + CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property)); - binding->addToObject(); + binding->addToObject(); + } } QML_END_INSTR(StoreV8Binding) @@ -1242,9 +1244,9 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt) while (!bindValues.isEmpty()) { QQmlAbstractBinding *b = bindValues.pop(); - if(b) { + if (b) { b->m_mePtr = 0; - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | + b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 0cd6ffd082..4c92598c32 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -52,6 +52,7 @@ #include <private/qqmlmetatype_p.h> #include <private/qqmltrace_p.h> #include <private/qqmlstringconverters_p.h> +#include <private/qqmlproperty_p.h> #include <QtQml/qqmlinfo.h> #include <QtCore/qnumeric.h> @@ -66,46 +67,53 @@ namespace { struct Register { typedef QQmlRegisterType Type; - void setUndefined() { dataType = UndefinedType; } - void setNull() { dataType = NullType; } - void setNaN() { setqreal(qSNaN()); } - bool isUndefined() const { return dataType == UndefinedType; } + inline void setUndefined() { dataType = UndefinedType; } + inline void setNull() { dataType = NullType; } + inline void setNaN() { setnumber(qSNaN()); } + inline bool isUndefined() const { return dataType == UndefinedType; } - void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; } - QObject *getQObject() const { return qobjectValue; } + inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; } + inline QObject *getQObject() const { return qobjectValue; } - void setqreal(qreal v) { qrealValue = v; dataType = QRealType; } - qreal getqreal() const { return qrealValue; } - qreal &getqrealref() { return qrealValue; } + inline void setnumber(double v) { numberValue = v; dataType = NumberType; } + inline double getnumber() const { return numberValue; } + inline double &getnumberref() { return numberValue; } - void setint(int v) { intValue = v; dataType = IntType; } - int getint() const { return intValue; } - int &getintref() { return intValue; } + inline void setfloat(float v) { floatValue = v; dataType = FloatType; } + inline float getfloat() const { return floatValue; } + inline float &getfloatref() { return floatValue; } - void setbool(bool v) { boolValue = v; dataType = BoolType; } - bool getbool() const { return boolValue; } - bool &getboolref() { return boolValue; } + inline void setint(int v) { intValue = v; dataType = IntType; } + inline int getint() const { return intValue; } + inline int &getintref() { return intValue; } - 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(); } + inline void setbool(bool v) { boolValue = v; dataType = BoolType; } + inline bool getbool() const { return boolValue; } + inline bool &getboolref() { return boolValue; } + + inline QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } + inline QString *getstringptr() { return (QString *)typeDataPtr(); } + inline QUrl *geturlptr() { return (QUrl *)typeDataPtr(); } + inline QColor *getcolorptr() { return (QColor *)typeDataPtr(); } + inline const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); } + inline const QString *getstringptr() const { return (QString *)typeDataPtr(); } + inline const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); } + inline const QColor *getcolorptr() const { return (QColor *)typeDataPtr(); } size_t dataSize() { return sizeof(data); } - void *typeDataPtr() { return (void *)&data; } - void *typeMemory() { return (void *)data; } - const void *typeDataPtr() const { return (void *)&data; } - const void *typeMemory() const { return (void *)data; } + inline void *typeDataPtr() { return (void *)&data; } + inline void *typeMemory() { return (void *)data; } + inline const void *typeDataPtr() const { return (void *)&data; } + inline const void *typeMemory() const { return (void *)data; } - Type gettype() const { return dataType; } - void settype(Type t) { dataType = t; } + inline Type gettype() const { return dataType; } + inline void settype(Type t) { dataType = t; } Type dataType; // Type of data union { QObject *qobjectValue; - qreal qrealValue; + double numberValue; + float floatValue; int intValue; bool boolValue; void *data[sizeof(QVariant)]; @@ -387,85 +395,6 @@ void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex) 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, QQmlContextData *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) { - // Preserve any valid percent-encoded octets supplied by the source - base.setEncodedUrl(var->toByteArray(), QUrl::TolerantMode); - } else if (vt == QVariant::String) { - base.setEncodedUrl(var->toString().toUtf8(), QUrl::TolerantMode); - } else { - if (ok) *ok = false; - return QUrl(); - } - } else if (type == QMetaType::QString) { - base.setEncodedUrl(reg->getstringptr()->toUtf8(), QUrl::TolerantMode); - } else { - if (ok) *ok = false; - return QUrl(); - } - - if (!base.isEmpty() && base.isRelative()) - return context->url.resolved(base); - else - return base; -} - static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4) { QVariant qtscript = qtscriptRaw; @@ -529,10 +458,29 @@ static void testBindingResult(const QString &binding, int line, int column, if (expression.hasError()) { iserror = true; qtscriptResult = "exception"; - } else { - qtscriptResult = testResultToString(value, isUndefined); + } else if (value.userType() != resultType) { + // Override the QMetaType conversions to make them more JS friendly. + if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString || + resultType == QMetaType::QUrl)) { + // number to string-like conversion. + value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16)); + } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) { + // url to bool conversion + value = QVariant::fromValue<bool>(!value.toUrl().isEmpty()); + } + + if (!value.isNull() && !value.convert(resultType)) { + iserror = true; + qtscriptResult = "exception"; + } else if (resultType == QMetaType::QUrl) { + // a V8 value was converted to QUrl. + value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl())); + } } + if (! iserror) + qtscriptResult = testResultToString(value, isUndefined); + if (isUndefined && result.isUndefined()) { return; } else if(isUndefined != result.isUndefined()) { @@ -557,8 +505,8 @@ static void testBindingResult(const QString &binding, int line, int column, case QMetaType::Int: v4value = result.getint(); break; - case QMetaType::QReal: - v4value = result.getqreal(); + case QMetaType::Double: + v4value = result.getnumber(); break; default: if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { @@ -621,15 +569,15 @@ static void throwException(int id, QQmlDelayedError *error, QQmlEnginePrivate::warning(context->engine, error->error); } -const qreal QV4Bindings::D32 = 4294967296.0; +const double QV4Bindings::D32 = 4294967296.0; -qint32 QV4Bindings::toInt32(qreal n) +qint32 QV4Bindings::toInt32(double n) { if (qIsNaN(n) || qIsInf(n) || (n == 0)) return 0; double sign = (n < 0) ? -1.0 : 1.0; - qreal abs_n = fabs(n); + double abs_n = fabs(n); n = ::fmod(sign * ::floor(abs_n), D32); const double D31 = D32 / 2.0; @@ -643,13 +591,13 @@ qint32 QV4Bindings::toInt32(qreal n) return qint32 (n); } -inline quint32 QV4Bindings::toUint32(qreal n) +inline quint32 QV4Bindings::toUint32(double n) { if (qIsNaN(n) || qIsInf(n) || (n == 0)) return 0; double sign = (n < 0) ? -1.0 : 1.0; - qreal abs_n = fabs(n); + double abs_n = fabs(n); n = ::fmod(sign * ::floor(abs_n), D32); @@ -665,6 +613,11 @@ inline quint32 QV4Bindings::toUint32(qreal n) goto exceptionExit; \ } +#define THROW_VALUE_EXCEPTION_STR(id, str) { \ + throwException((id), error, program, context, (str)); \ + goto exceptionExit; \ +} + #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString()) #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg)) @@ -791,13 +744,21 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, sub->bindings = this; sub->method = subIdx; } - reg.init((Register::Type)instr->fetchAndSubscribe.valueType); + + const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType; + reg.init(valueType); if (instr->fetchAndSubscribe.valueType >= FirstCleanupType) MARK_REGISTER(instr->fetchAndSubscribe.reg); QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors; accessors->read(object, instr->fetchAndSubscribe.property.accessorData, reg.typeDataPtr()); + if (valueType == FloatType) { + // promote floats + const double v = reg.getfloat(); + reg.setnumber(v); + } + if (accessors->notifier) { QQmlNotifier *notifier = 0; accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, ¬ifier); @@ -868,11 +829,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(UnaryNot, unaryop) - QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop) + QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop) { - registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal()); + registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber()); } - QML_V4_END_INSTR(UnaryMinusReal, unaryop) + QML_V4_END_INSTR(UnaryMinusNumber, unaryop) QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop) { @@ -880,11 +841,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(UnaryMinusInt, unaryop) - QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop) + QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop) { - registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal()); + registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber()); } - QML_V4_END_INSTR(UnaryPlusReal, unaryop) + QML_V4_END_INSTR(UnaryPlusNumber, unaryop) QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop) { @@ -901,14 +862,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertBoolToInt, unaryop) - QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop) + QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; Register &output = registers[instr->unaryop.output]; if (src.isUndefined()) output.setUndefined(); - else output.setqreal(src.getbool()); + else output.setnumber(src.getbool()); } - QML_V4_END_INSTR(ConvertBoolToReal, unaryop) + QML_V4_END_INSTR(ConvertBoolToNumber, unaryop) QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop) { @@ -932,14 +893,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertIntToBool, unaryop) - QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop) + QML_V4_BEGIN_INSTR(ConvertIntToNumber, 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())); + else output.setnumber(double(src.getint())); } - QML_V4_END_INSTR(ConvertIntToReal, unaryop) + QML_V4_END_INSTR(ConvertIntToNumber, unaryop) QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop) { @@ -954,25 +915,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertIntToString, unaryop) - QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToBool, 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); + else output.setbool(src.getnumber() != 0); } - QML_V4_END_INSTR(ConvertRealToBool, unaryop) + QML_V4_END_INSTR(ConvertNumberToBool, unaryop) - QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToInt, 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())); + else output.setint(toInt32(src.getnumber())); } - QML_V4_END_INSTR(ConvertRealToInt, unaryop) + QML_V4_END_INSTR(ConvertNumberToInt, unaryop) - QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop) { const Register &src = registers[instr->unaryop.src]; Register &output = registers[instr->unaryop.output]; @@ -980,11 +941,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, if (src.isUndefined()) { output.setUndefined(); } else { - new (output.getstringptr()) QString(QString::number(src.getqreal())); + new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16)); STRING_REGISTER(instr->unaryop.output); } } - QML_V4_END_INSTR(ConvertRealToString, unaryop) + QML_V4_END_INSTR(ConvertNumberToString, unaryop) QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop) { @@ -1026,7 +987,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertStringToInt, unaryop) - QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop) + QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; Register &output = registers[instr->unaryop.output]; @@ -1041,10 +1002,10 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, output.cleanupString(); MARK_CLEAN_REGISTER(instr->unaryop.output); } - output.setqreal(tmp.toNumber()); + output.setnumber(tmp.toNumber()); } } - QML_V4_END_INSTR(ConvertStringToReal, unaryop) + QML_V4_END_INSTR(ConvertStringToNumber, unaryop) QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop) { @@ -1190,75 +1151,75 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ResolveUrl, unaryop) - QML_V4_BEGIN_INSTR(MathSinReal, unaryop) + QML_V4_BEGIN_INSTR(MathSinNumber, 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())); + else output.setnumber(qSin(src.getnumber())); } - QML_V4_END_INSTR(MathSinReal, unaryop) + QML_V4_END_INSTR(MathSinNumber, unaryop) - QML_V4_BEGIN_INSTR(MathCosReal, unaryop) + QML_V4_BEGIN_INSTR(MathCosNumber, 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())); + else output.setnumber(qCos(src.getnumber())); } - QML_V4_END_INSTR(MathCosReal, unaryop) + QML_V4_END_INSTR(MathCosNumber, unaryop) - QML_V4_BEGIN_INSTR(MathAbsReal, unaryop) + QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; Register &output = registers[instr->unaryop.output]; if (src.isUndefined()) output.setUndefined(); - else output.setqreal(qAbs(src.getqreal())); + else output.setnumber(qAbs(src.getnumber())); } - QML_V4_END_INSTR(MathAbsReal, unaryop) + QML_V4_END_INSTR(MathAbsNumber, unaryop) - QML_V4_BEGIN_INSTR(MathRoundReal, unaryop) + QML_V4_BEGIN_INSTR(MathRoundNumber, 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())); + else output.setint(qRound(src.getnumber())); } - QML_V4_END_INSTR(MathRoundReal, unaryop) + QML_V4_END_INSTR(MathRoundNumber, unaryop) - QML_V4_BEGIN_INSTR(MathFloorReal, unaryop) + QML_V4_BEGIN_INSTR(MathFloorNumber, 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())); + else output.setint(qFloor(src.getnumber())); } - QML_V4_END_INSTR(MathFloorReal, unaryop) + QML_V4_END_INSTR(MathFloorNumber, unaryop) - QML_V4_BEGIN_INSTR(MathCeilReal, unaryop) + QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; Register &output = registers[instr->unaryop.output]; if (src.isUndefined()) output.setUndefined(); - else output.setint(qCeil(src.getqreal())); + else output.setint(qCeil(src.getnumber())); } - QML_V4_END_INSTR(MathCeilReal, unaryop) + QML_V4_END_INSTR(MathCeilNumber, unaryop) - QML_V4_BEGIN_INSTR(MathPIReal, unaryop) + QML_V4_BEGIN_INSTR(MathPINumber, unaryop) { - static const qreal qmlPI = 2.0 * qAsin(1.0); + static const double qmlPI = 2.0 * qAsin(1.0); Register &output = registers[instr->unaryop.output]; - output.setqreal(qmlPI); + output.setnumber(qmlPI); } - QML_V4_END_INSTR(MathPIReal, unaryop) + QML_V4_END_INSTR(MathPINumber, unaryop) QML_V4_BEGIN_INSTR(LoadNull, null_value) registers[instr->null_value.reg].setNull(); QML_V4_END_INSTR(LoadNull, null_value) - QML_V4_BEGIN_INSTR(LoadReal, real_value) - registers[instr->real_value.reg].setqreal(instr->real_value.value); - QML_V4_END_INSTR(LoadReal, real_value) + QML_V4_BEGIN_INSTR(LoadNumber, number_value) + registers[instr->number_value.reg].setnumber(instr->number_value.value); + QML_V4_END_INSTR(LoadNumber, number_value) QML_V4_BEGIN_INSTR(LoadInt, int_value) registers[instr->int_value.reg].setint(instr->int_value.value); @@ -1305,12 +1266,12 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(BitXorInt, binaryop) - QML_V4_BEGIN_INSTR(AddReal, binaryop) + QML_V4_BEGIN_INSTR(AddNumber, binaryop) { - registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() + - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() + + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(AddReal, binaryop) + QML_V4_END_INSTR(AddNumber, binaryop) QML_V4_BEGIN_INSTR(AddString, binaryop) { @@ -1324,36 +1285,33 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(AddString, binaryop) - QML_V4_BEGIN_INSTR(SubReal, binaryop) + QML_V4_BEGIN_INSTR(SubNumber, binaryop) { - registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() - - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() - + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(SubReal, binaryop) + QML_V4_END_INSTR(SubNumber, binaryop) - QML_V4_BEGIN_INSTR(MulReal, binaryop) + QML_V4_BEGIN_INSTR(MulNumber, binaryop) { - registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() * - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() * + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(MulReal, binaryop) + QML_V4_END_INSTR(MulNumber, binaryop) - QML_V4_BEGIN_INSTR(DivReal, binaryop) + QML_V4_BEGIN_INSTR(DivNumber, binaryop) { - registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() / - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() / + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(DivReal, binaryop) + QML_V4_END_INSTR(DivNumber, binaryop) - QML_V4_BEGIN_INSTR(ModReal, binaryop) + QML_V4_BEGIN_INSTR(ModNumber, 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())); + target.setnumber(::fmod(left.getnumber(), right.getnumber())); } QML_V4_END_INSTR(ModInt, binaryop) @@ -1378,61 +1336,61 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(URShiftInt, binaryop) - QML_V4_BEGIN_INSTR(GtReal, binaryop) + QML_V4_BEGIN_INSTR(GtNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() > - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() > + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(GtReal, binaryop) + QML_V4_END_INSTR(GtNumber, binaryop) - QML_V4_BEGIN_INSTR(LtReal, binaryop) + QML_V4_BEGIN_INSTR(LtNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() < - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() < + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(LtReal, binaryop) + QML_V4_END_INSTR(LtNumber, binaryop) - QML_V4_BEGIN_INSTR(GeReal, binaryop) + QML_V4_BEGIN_INSTR(GeNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >= - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >= + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(GeReal, binaryop) + QML_V4_END_INSTR(GeNumber, binaryop) - QML_V4_BEGIN_INSTR(LeReal, binaryop) + QML_V4_BEGIN_INSTR(LeNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <= - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <= + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(LeReal, binaryop) + QML_V4_END_INSTR(LeNumber, binaryop) - QML_V4_BEGIN_INSTR(EqualReal, binaryop) + QML_V4_BEGIN_INSTR(EqualNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() == + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(EqualReal, binaryop) + QML_V4_END_INSTR(EqualNumber, binaryop) - QML_V4_BEGIN_INSTR(NotEqualReal, binaryop) + QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() != + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(NotEqualReal, binaryop) + QML_V4_END_INSTR(NotEqualNumber, binaryop) - QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop) + QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() == + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(StrictEqualReal, binaryop) + QML_V4_END_INSTR(StrictEqualNumber, binaryop) - QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop) + QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop) { - registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != - registers[instr->binaryop.right].getqreal()); + registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() != + registers[instr->binaryop.right].getnumber()); } - QML_V4_END_INSTR(StrictNotEqualReal, binaryop) + QML_V4_END_INSTR(StrictNotEqualNumber, binaryop) QML_V4_BEGIN_INSTR(GtString, binaryop) { @@ -1578,25 +1536,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(StrictNotEqualObject, binaryop) - QML_V4_BEGIN_INSTR(MathMaxReal, binaryop) + QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop) { const Register &left = registers[instr->binaryop.left]; const Register &right = registers[instr->binaryop.right]; Register &output = registers[instr->binaryop.output]; if (left.isUndefined() || right.isUndefined()) output.setUndefined(); - else output.setqreal(qMax(left.getqreal(), right.getqreal())); + else output.setnumber(qMax(left.getnumber(), right.getnumber())); } - QML_V4_END_INSTR(MathMaxReal, binaryop) + QML_V4_END_INSTR(MathMaxNumber, binaryop) - QML_V4_BEGIN_INSTR(MathMinReal, binaryop) + QML_V4_BEGIN_INSTR(MathMinNumber, binaryop) { const Register &left = registers[instr->binaryop.left]; const Register &right = registers[instr->binaryop.right]; Register &output = registers[instr->binaryop.output]; if (left.isUndefined() || right.isUndefined()) output.setUndefined(); - else output.setqreal(qMin(left.getqreal(), right.getqreal())); + else output.setnumber(qMin(left.getnumber(), right.getnumber())); } - QML_V4_END_INSTR(MathMinReal, binaryop) + QML_V4_END_INSTR(MathMinNumber, binaryop) QML_V4_BEGIN_INSTR(NewString, construct) { @@ -1625,11 +1583,17 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, if (!object) { THROW_EXCEPTION(instr->fetch.exceptionId); } else { - reg.init((Register::Type)instr->fetch.valueType); + const Register::Type valueType = (Register::Type)instr->fetch.valueType; + reg.init(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); + if (valueType == FloatType) { + // promote floats + const double v = reg.getfloat(); + reg.setnumber(v); + } } } QML_V4_END_INSTR(Fetch, fetch) @@ -1649,6 +1613,30 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, if (data.isUndefined()) THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value")); + if (data.gettype() == QObjectStarType) { + if (QObject *dataObject = data.getQObject()) { + const QMetaObject *dataMo = dataObject->metaObject(); + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + QMetaProperty receiver = output->metaObject()->property(instr->store.index); + const QMetaObject *receiverMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, receiver.userType()); + + // Verify that these types are compatible + if (!QQmlPropertyPrivate::canConvert(dataMo, receiverMo)) { + THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") + + QLatin1String(dataMo->className()) + + QLatin1String(" to ") + + QLatin1String(receiverMo->className())); + } + } + } + + if (instr->store.valueType == FloatType) { + // cast numbers to floats + const float v = (float) data.getnumber(); + data.setfloat(v); + } + int status = -1; void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags }; QMetaObject::metacall(output, QMetaObject::WriteProperty, @@ -1687,22 +1675,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, executedBlocks |= instr->blockop.block; QML_V4_END_INSTR(Block, blockop) - // XXX not applicable in v8 - QML_V4_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_V4_END_INSTR(InitString, initstring) - QML_V4_BEGIN_INSTR(CleanupRegister, cleanup) registers[instr->cleanup.reg].cleanup(); QML_V4_END_INSTR(CleanupRegister, cleanup) + QML_V4_BEGIN_INSTR(Throw, throwop) + THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr()); + QML_V4_END_INSTR(Throw, throwop) + #ifdef QML_THREADED_INTERPRETER // nothing to do #else diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h index 1824fa4ee9..3a7d175d7b 100644 --- a/src/qml/qml/v4/qv4bindings_p.h +++ b/src/qml/qml/v4/qv4bindings_p.h @@ -141,9 +141,9 @@ private: inline void subscribeId(QQmlContextData *p, int idIndex, int subIndex); inline void subscribe(QObject *o, int notifyIndex, int subIndex); - inline static qint32 toInt32(qreal n); - static const qreal D32; - static quint32 toUint32(qreal n); + inline static qint32 toInt32(double n); + static const double D32; + static quint32 toUint32(double n); }; diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index c9495e8987..045a14fbb5 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -62,7 +62,9 @@ static bool qmlEnableV4 = true; using namespace QQmlJS; QV4CompilerPrivate::QV4CompilerPrivate() - : _function(0) , _block(0) , _discarded(false), registerCount(0) + : subscriptionOffset(0) + , _function(0) , _block(0) , _discarded(false), registerCount(0) + , bindingLine(0), bindingColumn(0) { } @@ -73,6 +75,8 @@ void QV4CompilerPrivate::trace(int line, int column) { bytecode.clear(); + this->bindingLine = line; + this->bindingColumn = column; this->currentReg = _function->tempCount; this->registerCount = qMax(this->registerCount, this->currentReg); @@ -226,8 +230,9 @@ void QV4CompilerPrivate::visitConst(IR::Const *e) gen(i); } break; - case IR::RealType: { - Instr::LoadReal i; + case IR::FloatType: + case IR::NumberType: { + Instr::LoadNumber i; i.reg = currentReg; i.value = e->value; gen(i); @@ -316,7 +321,7 @@ void QV4CompilerPrivate::visitName(IR::Name *e) Instr::LoadAttached attached; attached.output = currentReg; attached.reg = currentReg; - attached.exceptionId = exceptionId(e->line, e->column); + attached.exceptionId = exceptionId(bindingLine, bindingColumn); if (e->declarativeType->attachedPropertiesId() == -1) discard(); attached.id = e->declarativeType->attachedPropertiesId(); @@ -351,8 +356,11 @@ void QV4CompilerPrivate::visitName(IR::Name *e) QQmlRegisterType regType; switch (propTy) { - case QMetaType::QReal: - regType = QRealType; + case QMetaType::Float: + regType = FloatType; + break; + case QMetaType::Double: + regType = NumberType; break; case QMetaType::Bool: regType = BoolType; @@ -373,7 +381,7 @@ void QV4CompilerPrivate::visitName(IR::Name *e) default: if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { regType = PODValueType; - } else if (QQmlMetaType::isQObject(propTy)) { + } else if (engine->metaObjectForType(propTy)) { regType = QObjectStarType; } else { if (qmlVerboseCompiler()) @@ -458,14 +466,14 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e) } break; case IR::OpUMinus: - if (e->expr->type == IR::RealType) { - Instr::UnaryMinusReal i; + if (IR::isRealType(e->expr->type)) { + Instr::UnaryMinusNumber i; i.output = currentReg; i.src = src; gen(i); } else if (e->expr->type == IR::IntType) { - convertToReal(e->expr, currentReg); - Instr::UnaryMinusReal i; + convertToNumber(e->expr, currentReg); + Instr::UnaryMinusNumber i; i.output = currentReg; i.src = src; gen(i); @@ -475,14 +483,14 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e) break; case IR::OpUPlus: - if (e->expr->type == IR::RealType) { - Instr::UnaryPlusReal i; + if (IR::isRealType(e->expr->type)) { + Instr::UnaryPlusNumber i; i.output = currentReg; i.src = src; gen(i); } else if (e->expr->type == IR::IntType) { - convertToReal(e->expr, currentReg); - Instr::UnaryPlusReal i; + convertToNumber(e->expr, currentReg); + Instr::UnaryPlusNumber i; i.output = currentReg; i.src = src; gen(i); @@ -522,25 +530,26 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e) } // switch } -void QV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg) +void QV4CompilerPrivate::convertToNumber(IR::Expr *expr, int reg) { - if (expr->type == IR::RealType) + if (expr->type == IR::NumberType) return; switch (expr->type) { case IR::BoolType: { - Instr::ConvertBoolToReal i; + Instr::ConvertBoolToNumber i; i.output = i.src = reg; gen(i); } break; case IR::IntType: { - Instr::ConvertIntToReal i; + Instr::ConvertIntToNumber i; i.output = i.src = reg; gen(i); } break; - case IR::RealType: + case IR::FloatType: + case IR::NumberType: // nothing to do return; @@ -566,8 +575,9 @@ void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg) // nothing to do return; - case IR::RealType: { - Instr::ConvertRealToInt i; + case IR::FloatType: + case IR::NumberType: { + Instr::ConvertNumberToInt i; i.output = i.src = reg; gen(i); } break; @@ -594,8 +604,9 @@ void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg) gen(i); } break; - case IR::RealType: { - Instr::ConvertRealToBool i; + case IR::FloatType: + case IR::NumberType: { + Instr::ConvertNumberToBool i; i.output = i.src = reg; gen(i); } return; @@ -643,19 +654,19 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e) case IR::OpAdd: if (e->type == IR::StringType) return V4Instr::AddString; - return V4Instr::AddReal; + return V4Instr::AddNumber; case IR::OpSub: - return V4Instr::SubReal; + return V4Instr::SubNumber; case IR::OpMul: - return V4Instr::MulReal; + return V4Instr::MulNumber; case IR::OpDiv: - return V4Instr::DivReal; + return V4Instr::DivNumber; case IR::OpMod: - return V4Instr::ModReal; + return V4Instr::ModNumber; case IR::OpLShift: return V4Instr::LShiftInt; @@ -669,50 +680,50 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e) case IR::OpGt: if (e->left->type == IR::StringType) return V4Instr::GtString; - return V4Instr::GtReal; + return V4Instr::GtNumber; case IR::OpLt: if (e->left->type == IR::StringType) return V4Instr::LtString; - return V4Instr::LtReal; + return V4Instr::LtNumber; case IR::OpGe: if (e->left->type == IR::StringType) return V4Instr::GeString; - return V4Instr::GeReal; + return V4Instr::GeNumber; case IR::OpLe: if (e->left->type == IR::StringType) return V4Instr::LeString; - return V4Instr::LeReal; + return V4Instr::LeNumber; case IR::OpEqual: if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType) return V4Instr::EqualObject; if (e->left->type == IR::StringType) return V4Instr::EqualString; - return V4Instr::EqualReal; + return V4Instr::EqualNumber; case IR::OpNotEqual: if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType) return V4Instr::NotEqualObject; if (e->left->type == IR::StringType) return V4Instr::NotEqualString; - return V4Instr::NotEqualReal; + return V4Instr::NotEqualNumber; case IR::OpStrictEqual: if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType) return V4Instr::StrictEqualObject; if (e->left->type == IR::StringType) return V4Instr::StrictEqualString; - return V4Instr::StrictEqualReal; + return V4Instr::StrictEqualNumber; case IR::OpStrictNotEqual: if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType) return V4Instr::StrictNotEqualObject; if (e->left->type == IR::StringType) return V4Instr::StrictNotEqualString; - return V4Instr::StrictNotEqualReal; + return V4Instr::StrictNotEqualNumber; case IR::OpAnd: case IR::OpOr: @@ -733,12 +744,26 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e) int left = currentReg; int right = currentReg + 1; - traceExpression(e->left, left); - traceExpression(e->right, right); + if (e->left->asTemp() && e->type != IR::StringType) + left = e->left->asTemp()->index; + else + traceExpression(e->left, left); - // At this point it is possible that the type of the - // subexpressions is different. This can happen because - // we keep BINOP expressions in HIR. + 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: @@ -766,8 +791,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e) case IR::OpAdd: if (e->type != IR::StringType) { - convertToReal(e->left, left); - convertToReal(e->right, right); + convertToNumber(e->left, left); + convertToNumber(e->right, right); } break; @@ -775,8 +800,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e) case IR::OpMul: case IR::OpDiv: case IR::OpMod: - convertToReal(e->left, left); - convertToReal(e->right, right); + convertToNumber(e->left, left); + convertToNumber(e->right, right); break; case IR::OpGt: @@ -788,8 +813,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e) case IR::OpStrictEqual: case IR::OpStrictNotEqual: if (e->left->type >= IR::FirstNumberType) { - convertToReal(e->left, left); - convertToReal(e->right, right); + convertToNumber(e->left, left); + convertToNumber(e->right, right); } break; @@ -813,7 +838,7 @@ void QV4CompilerPrivate::visitCall(IR::Call *call) { if (IR::Name *name = call->base->asName()) { IR::Expr *arg = call->onlyArgument(); - if (arg != 0 && arg->type == IR::RealType) { + if (arg != 0 && IR::isRealType(arg->type)) { traceExpression(arg, currentReg); switch (name->builtin) { @@ -821,37 +846,37 @@ void QV4CompilerPrivate::visitCall(IR::Call *call) break; case IR::MathSinBultinFunction: { - Instr::MathSinReal i; + Instr::MathSinNumber i; i.output = i.src = currentReg; gen(i); } return; case IR::MathCosBultinFunction: { - Instr::MathCosReal i; + Instr::MathCosNumber i; i.output = i.src = currentReg; gen(i); } return; case IR::MathAbsBuiltinFunction: { - Instr::MathAbsReal i; + Instr::MathAbsNumber i; i.output = i.src = currentReg; gen(i); } return; case IR::MathRoundBultinFunction: { - Instr::MathRoundReal i; + Instr::MathRoundNumber i; i.output = i.src = currentReg; gen(i); } return; case IR::MathFloorBultinFunction: { - Instr::MathFloorReal i; + Instr::MathFloorNumber i; i.output = i.src = currentReg; gen(i); } return; case IR::MathCeilBuiltinFunction: { - Instr::MathCeilReal i; + Instr::MathCeilNumber i; i.output = i.src = currentReg; gen(i); } return; @@ -869,21 +894,21 @@ void QV4CompilerPrivate::visitCall(IR::Call *call) IR::Expr *arg1 = call->args->expr; IR::Expr *arg2 = call->args->next->expr; - if (arg1 != 0 && arg1->type == IR::RealType && - arg2 != 0 && arg2->type == IR::RealType) { + if (arg1 != 0 && IR::isRealType(arg1->type) && + arg2 != 0 && IR::isRealType(arg2->type)) { traceExpression(arg1, currentReg); traceExpression(arg2, currentReg + 1); if (name->builtin == IR::MathMaxBuiltinFunction) { - Instr::MathMaxReal i; + Instr::MathMaxNumber i; i.left = currentReg; i.right = currentReg + 1; i.output = currentReg; gen(i); return; } else if (name->builtin == IR::MathMinBuiltinFunction) { - Instr::MathMinReal i; + Instr::MathMinNumber i; i.left = currentReg; i.right = currentReg + 1; i.output = currentReg; @@ -917,7 +942,17 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) quint8 dest = target->index; - if (target->type != s->source->type) { + IR::Type targetTy = s->target->type; + IR::Type sourceTy = s->source->type; + + // promote the floats + if (sourceTy == IR::FloatType) + sourceTy = IR::NumberType; + + if (targetTy == IR::FloatType) + targetTy = IR::NumberType; + + if (sourceTy != targetTy) { quint8 src = dest; if (IR::Temp *t = s->source->asTemp()) @@ -926,8 +961,6 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) traceExpression(s->source, dest); V4Instr::Type opcode = V4Instr::Noop; - IR::Type targetTy = s->target->type; - IR::Type sourceTy = s->source->type; if (sourceTy == IR::UrlType) { switch (targetTy) { @@ -937,13 +970,22 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) // url-to-xxx conversions. break; default: { + if (s->isMoveForReturn) { + V4Instr instr; + instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn); + registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2") + .arg(QLatin1String(IR::typeName(sourceTy))) + .arg(QLatin1String(IR::typeName(targetTy))))); + instr.throwop.message = dest; + gen(V4Instr::Throw, instr); + return; + } // generate a UrlToString conversion and fix // the type of the source expression. V4Instr conv; - conv.unaryop.output = V4Instr::ConvertUrlToString; + conv.unaryop.output = src; conv.unaryop.src = src; - gen(opcode, conv); - + gen(V4Instr::ConvertUrlToString, conv); sourceTy = IR::StringType; break; } @@ -953,7 +995,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) if (targetTy == IR::BoolType) { switch (sourceTy) { case IR::IntType: opcode = V4Instr::ConvertIntToBool; break; - case IR::RealType: opcode = V4Instr::ConvertRealToBool; break; + case IR::NumberType: opcode = V4Instr::ConvertNumberToBool; break; case IR::StringType: opcode = V4Instr::ConvertStringToBool; break; case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break; case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break; @@ -963,33 +1005,44 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) } else if (targetTy == IR::IntType) { switch (sourceTy) { case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break; - case IR::RealType: { + case IR::NumberType: { if (s->isMoveForReturn) - opcode = V4Instr::MathRoundReal; + opcode = V4Instr::MathRoundNumber; else - opcode = V4Instr::ConvertRealToInt; + opcode = V4Instr::ConvertNumberToInt; break; } case IR::StringType: opcode = V4Instr::ConvertStringToInt; break; default: break; } // switch - } else if (targetTy == IR::RealType) { + } else if (IR::isRealType(targetTy)) { switch (sourceTy) { - case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break; - case IR::IntType: opcode = V4Instr::ConvertIntToReal; break; - case IR::StringType: opcode = V4Instr::ConvertStringToReal; break; + case IR::BoolType: opcode = V4Instr::ConvertBoolToNumber; break; + case IR::IntType: opcode = V4Instr::ConvertIntToNumber; break; + case IR::StringType: opcode = V4Instr::ConvertStringToNumber; break; default: break; } // switch } else if (targetTy == IR::StringType) { switch (sourceTy) { case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break; case IR::IntType: opcode = V4Instr::ConvertIntToString; break; - case IR::RealType: opcode = V4Instr::ConvertRealToString; break; + case IR::NumberType: opcode = V4Instr::ConvertNumberToString; break; case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break; case IR::ColorType: opcode = V4Instr::ConvertColorToString; break; default: break; } // switch } else if (targetTy == IR::UrlType) { + if (s->isMoveForReturn && sourceTy != IR::StringType) { + V4Instr instr; + instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn); + registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2") + .arg(QLatin1String(IR::typeName(sourceTy))) + .arg(QLatin1String(IR::typeName(targetTy))))); + instr.throwop.message = dest; + gen(V4Instr::Throw, instr); + return; + } + V4Instr convToString; convToString.unaryop.output = dest; convToString.unaryop.src = src; @@ -998,7 +1051,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) switch (sourceTy) { case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break; case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break; - case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break; + case IR::NumberType: gen(V4Instr::ConvertNumberToString, convToString); sourceTy = IR::StringType; break; case IR::ColorType: gen(V4Instr::ConvertColorToString, convToString); sourceTy = IR::StringType; break; default: break; } // switch @@ -1094,8 +1147,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s) case IR::IntType: test.regType = QMetaType::Int; break; - case IR::RealType: - test.regType = QMetaType::QReal; + case IR::FloatType: + case IR::NumberType: + test.regType = QMetaType::Double; break; default: discard(); @@ -1108,6 +1162,7 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s) store.output = 0; store.index = expression->property->index; store.reg = storeReg; + store.valueType = s->type == IR::FloatType ? FloatType : 0; store.exceptionId = exceptionId(s->line, s->column); gen(store); } @@ -1119,7 +1174,6 @@ void QV4Compiler::dump(const QByteArray &programData) 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(); @@ -1137,8 +1191,8 @@ void QV4CompilerPrivate::resetInstanceState() data = committed.data; exceptions = committed.exceptions; usedSubscriptionIds.clear(); - subscriptionIds = committed.subscriptionIds; - registeredStrings = committed.registeredStrings; + subscriptionIds.clear(); + subscriptionOffset = committed.subscriptionCount; bytecode.clear(); patches.clear(); pool.clear(); @@ -1159,8 +1213,9 @@ int QV4CompilerPrivate::commitCompile() committed.bytecode.append(bytecode.constData(), bytecode.size()); committed.data = data; committed.exceptions = exceptions; - committed.subscriptionIds = subscriptionIds; - committed.registeredStrings = registeredStrings; + committed.subscriptionCount = subscriptionOffset + subscriptionIds.count(); + if (bindingsDump()) + committed.subscriptions.append(subscriptionIds); return rv; } @@ -1212,7 +1267,7 @@ bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node) qerr << endl; } - if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF || registerCount > 31) + if (discarded || subscriptionIds.count() > 0xFFFF || registerCount > 31) return false; return true; @@ -1236,32 +1291,6 @@ int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str) return reg; } -// Returns an identifier offset -int QV4CompilerPrivate::registerString(const QString &string) -{ - Q_ASSERT(!string.isEmpty()); - - QPair<int, int> *iter = registeredStrings.value(string); - - if (!iter) { - 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 = ®isteredStrings[string]; - *iter = qMakePair(registeredStrings.count(), rv); - } - - Instr::InitString reg; - reg.offset = iter->first; - reg.dataIdx = iter->second; - gen(reg); - return reg.offset; -} - /*! Returns true if the current expression has not already subscribed to \a sub in currentBlockMask. */ @@ -1285,7 +1314,7 @@ int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub) QString str = sub.join(QLatin1String(".")); int *iter = subscriptionIds.value(str); if (!iter) { - int count = subscriptionIds.count(); + int count = subscriptionOffset + subscriptionIds.count(); iter = &subscriptionIds[str]; *iter = count; } @@ -1384,8 +1413,8 @@ QByteArray QV4CompilerPrivate::buildSignalTable() const QVector<quint32> header; QVector<quint32> data; - for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) { - header.append(committed.subscriptionIds.count() + data.count()); + for (int ii = 0; ii < committed.subscriptionCount; ++ii) { + header.append(committed.subscriptionCount + data.count()); const QList<QPair<int, quint32> > &bindings = table[ii]; data.append(bindings.count()); for (int jj = 0; jj < bindings.count(); ++jj) { @@ -1443,8 +1472,7 @@ QByteArray QV4Compiler::program() const data += d->buildExceptionData(); prog.dataLength = 4 * ((data.size() + 3) / 4); - prog.subscriptions = d->committed.subscriptionIds.count(); - prog.identifiers = d->committed.registeredStrings.count(); + prog.subscriptions = d->committed.subscriptionCount; prog.instructionCount = bytecode.count(); int size = sizeof(QV4Program) + bytecode.count(); size += prog.dataLength; @@ -1461,12 +1489,13 @@ QByteArray QV4Compiler::program() const if (bindingsDump()) { qWarning().nospace() << "Subscription slots:"; - for (QQmlAssociationList<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin(); - iter != d->committed.subscriptionIds.end(); - ++iter) { - qWarning().nospace() << " " << iter->first << "\t-> " << iter->second; + QQmlAssociationList<QString, int> subscriptionIds; + foreach (subscriptionIds, d->committed.subscriptions) { + for (QQmlAssociationList<QString, int>::ConstIterator iter = subscriptionIds.begin(); + iter != subscriptionIds.end(); ++iter) { + qWarning().nospace() << " " << iter->first << "\t-> " << iter->second; + } } - QV4Compiler::dump(programData); } diff --git a/src/qml/qml/v4/qv4compiler_p_p.h b/src/qml/qml/v4/qv4compiler_p_p.h index a9209d978f..0c06ade87f 100644 --- a/src/qml/qml/v4/qv4compiler_p_p.h +++ b/src/qml/qml/v4/qv4compiler_p_p.h @@ -128,8 +128,6 @@ public: bool compile(QQmlJS::AST::Node *); int registerLiteralString(quint8 reg, const QStringRef &); - int registerString(const QString &); - QQmlAssociationList<QString, QPair<int, int> > registeredStrings; QByteArray data; bool blockNeedsSubscription(const QStringList &); @@ -141,7 +139,7 @@ public: QVector<quint64> exceptions; QQmlAssociationList<int, quint32> usedSubscriptionIds; - + int subscriptionOffset; QQmlAssociationList<QString, int> subscriptionIds; QQmlJS::Bytecode bytecode; @@ -156,17 +154,17 @@ public: QQmlPool pool; // Committed binding data - struct { + struct Committed { + Committed(): subscriptionCount(0) {} QList<int> offsets; QList<QQmlAssociationList<int, quint32> > dependencies; //QQmlJS::Bytecode bytecode; QByteArray bytecode; QByteArray data; - QQmlAssociationList<QString, int> subscriptionIds; QVector<quint64> exceptions; - - QQmlAssociationList<QString, QPair<int, int> > registeredStrings; + int subscriptionCount; + QList<QQmlAssociationList<QString, int> > subscriptions; int count() const { return offsets.count(); } } committed; @@ -174,7 +172,7 @@ public: QByteArray buildSignalTable() const; QByteArray buildExceptionData() const; - void convertToReal(QQmlJS::IR::Expr *expr, int reg); + void convertToNumber(QQmlJS::IR::Expr *expr, int reg); void convertToInt(QQmlJS::IR::Expr *expr, int reg); void convertToBool(QQmlJS::IR::Expr *expr, int reg); quint8 instructionOpcode(QQmlJS::IR::Binop *e); @@ -235,6 +233,8 @@ private: bool usedSubscriptionIdsChanged; quint32 currentBlockMask; + int bindingLine; + int bindingColumn; }; diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp index cb6ff40589..ecd4f01ef3 100644 --- a/src/qml/qml/v4/qv4instruction.cpp +++ b/src/qml/qml/v4/qv4instruction.cpp @@ -123,14 +123,14 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::UnaryNot: INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::UnaryMinusReal: - INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::UnaryMinusNumber: + INSTR_DUMP << "\t" << "UnaryMinusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::UnaryMinusInt: INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::UnaryPlusReal: - INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::UnaryPlusNumber: + INSTR_DUMP << "\t" << "UnaryPlusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::UnaryPlusInt: INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; @@ -138,8 +138,8 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertBoolToInt: INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertBoolToReal: - INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertBoolToNumber: + INSTR_DUMP << "\t" << "ConvertBoolToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertBoolToString: INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; @@ -147,20 +147,20 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertIntToBool: INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertIntToReal: - INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertIntToNumber: + INSTR_DUMP << "\t" << "ConvertIntToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertIntToString: INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertRealToBool: - INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertNumberToBool: + INSTR_DUMP << "\t" << "ConvertNumberToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertRealToInt: - INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertNumberToInt: + INSTR_DUMP << "\t" << "ConvertNumberToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertRealToString: - INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertNumberToString: + INSTR_DUMP << "\t" << "ConvertNumberToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertStringToBool: INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; @@ -168,8 +168,8 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertStringToInt: INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::ConvertStringToReal: - INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::ConvertStringToNumber: + INSTR_DUMP << "\t" << "ConvertStringToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::ConvertStringToUrl: INSTR_DUMP << "\t" << "ConvertStringToUrl" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; @@ -198,32 +198,32 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ResolveUrl: INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathSinReal: - INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathSinNumber: + INSTR_DUMP << "\t" << "MathSinNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathCosReal: - INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathCosNumber: + INSTR_DUMP << "\t" << "MathCosNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathAbsReal: - INSTR_DUMP << "\t" << "MathAbsReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathAbsNumber: + INSTR_DUMP << "\t" << "MathAbsNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathRoundReal: - INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathRoundNumber: + INSTR_DUMP << "\t" << "MathRoundNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathFloorReal: - INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathFloorNumber: + INSTR_DUMP << "\t" << "MathFloorNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathCeilReal: - INSTR_DUMP << "\t" << "MathCeilReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathCeilNumber: + INSTR_DUMP << "\t" << "MathCeilNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; - case V4Instr::MathPIReal: - INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + case V4Instr::MathPINumber: + INSTR_DUMP << "\t" << "MathPINumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; case V4Instr::LoadNull: INSTR_DUMP << "\t" << "LoadNull" << "\t\t" << "Constant(null) -> Output_Reg(" << i->null_value.reg << ")"; break; - case V4Instr::LoadReal: - INSTR_DUMP << "\t" << "LoadReal" << "\t\t" << "Constant(" << i->real_value.value << ") -> Output_Reg(" << i->real_value.reg << ")"; + case V4Instr::LoadNumber: + INSTR_DUMP << "\t" << "LoadNumber" << "\t\t" << "Constant(" << i->number_value.value << ") -> Output_Reg(" << i->number_value.reg << ")"; break; case V4Instr::LoadInt: INSTR_DUMP << "\t" << "LoadInt" << "\t\t\t" << "Constant(" << i->int_value.value << ") -> Output_Reg(" << i->int_value.reg << ")"; @@ -249,23 +249,23 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::BitXorInt: INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::AddReal: - INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::AddNumber: + INSTR_DUMP << "\t" << "AddNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; case V4Instr::AddString: INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::SubReal: - INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::SubNumber: + INSTR_DUMP << "\t" << "SubNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::MulReal: - INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::MulNumber: + INSTR_DUMP << "\t" << "MulNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::DivReal: - INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::DivNumber: + INSTR_DUMP << "\t" << "DivNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::ModReal: - INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::ModNumber: + INSTR_DUMP << "\t" << "ModNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; case V4Instr::LShiftInt: INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; @@ -276,29 +276,29 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::URShiftInt: INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::GtReal: - INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::GtNumber: + INSTR_DUMP << "\t" << "GtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::LtReal: - INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::LtNumber: + INSTR_DUMP << "\t" << "LtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::GeReal: - INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::GeNumber: + INSTR_DUMP << "\t" << "GeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::LeReal: - INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::LeNumber: + INSTR_DUMP << "\t" << "LeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::EqualReal: - INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::EqualNumber: + INSTR_DUMP << "\t" << "EqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::NotEqualReal: - INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::NotEqualNumber: + INSTR_DUMP << "\t" << "NotEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::StrictEqualReal: - INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::StrictEqualNumber: + INSTR_DUMP << "\t" << "StrictEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::StrictNotEqualReal: - INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::StrictNotEqualNumber: + INSTR_DUMP << "\t" << "StrictNotEqualNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; case V4Instr::GtString: INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; @@ -336,11 +336,11 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::StrictNotEqualObject: INSTR_DUMP << "\t" << "StrictNotEqualObject" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::MathMaxReal: - INSTR_DUMP << "\t" << "MathMaxReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::MathMaxNumber: + INSTR_DUMP << "\t" << "MathMaxNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; - case V4Instr::MathMinReal: - INSTR_DUMP << "\t" << "MathMinReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; + case V4Instr::MathMinNumber: + INSTR_DUMP << "\t" << "MathMinNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")"; break; case V4Instr::NewString: INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << i->construct.reg << ")"; @@ -376,12 +376,12 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::Branch: INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + i->branchop.offset) << ")"; break; - case V4Instr::InitString: - INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << i->initstring.dataIdx << ") -> String_Slot(" << i->initstring.offset << ")"; - break; case V4Instr::Block: INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(i->blockop.block, 16).constData() << ")"; break; + case V4Instr::Throw: + INSTR_DUMP << "\t" << "Throw" << "\t\t\t" << "InputReg(" << i->throwop.message << ")"; + break; default: INSTR_DUMP << "\t" << "Unknown"; break; diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h index 239cb362cc..310bfbaff5 100644 --- a/src/qml/qml/v4/qv4instruction_p.h +++ b/src/qml/qml/v4/qv4instruction_p.h @@ -76,22 +76,22 @@ QT_BEGIN_NAMESPACE F(LoadModuleObject, load) \ F(LoadAttached, attached) \ F(UnaryNot, unaryop) \ - F(UnaryMinusReal, unaryop) \ + F(UnaryMinusNumber, unaryop) \ F(UnaryMinusInt, unaryop) \ - F(UnaryPlusReal, unaryop) \ + F(UnaryPlusNumber, unaryop) \ F(UnaryPlusInt, unaryop) \ F(ConvertBoolToInt, unaryop) \ - F(ConvertBoolToReal, unaryop) \ + F(ConvertBoolToNumber, unaryop) \ F(ConvertBoolToString, unaryop) \ F(ConvertIntToBool, unaryop) \ - F(ConvertIntToReal, unaryop) \ + F(ConvertIntToNumber, unaryop) \ F(ConvertIntToString, unaryop) \ - F(ConvertRealToBool, unaryop) \ - F(ConvertRealToInt, unaryop) \ - F(ConvertRealToString, unaryop) \ + F(ConvertNumberToBool, unaryop) \ + F(ConvertNumberToInt, unaryop) \ + F(ConvertNumberToString, unaryop) \ F(ConvertStringToBool, unaryop) \ F(ConvertStringToInt, unaryop) \ - F(ConvertStringToReal, unaryop) \ + F(ConvertStringToNumber, unaryop) \ F(ConvertStringToUrl, unaryop) \ F(ConvertStringToColor, unaryop) \ F(ConvertUrlToBool, unaryop) \ @@ -101,15 +101,15 @@ QT_BEGIN_NAMESPACE F(ConvertObjectToBool, unaryop) \ F(ConvertNullToObject, unaryop) \ F(ResolveUrl, unaryop) \ - F(MathSinReal, unaryop) \ - F(MathCosReal, unaryop) \ - F(MathAbsReal, unaryop) \ - F(MathRoundReal, unaryop) \ - F(MathFloorReal, unaryop) \ - F(MathCeilReal, unaryop) \ - F(MathPIReal, unaryop) \ + F(MathSinNumber, unaryop) \ + F(MathCosNumber, unaryop) \ + F(MathAbsNumber, unaryop) \ + F(MathRoundNumber, unaryop) \ + F(MathFloorNumber, unaryop) \ + F(MathCeilNumber, unaryop) \ + F(MathPINumber, unaryop) \ F(LoadNull, null_value) \ - F(LoadReal, real_value) \ + F(LoadNumber, number_value) \ F(LoadInt, int_value) \ F(LoadBool, bool_value) \ F(LoadString, string_value) \ @@ -118,23 +118,23 @@ QT_BEGIN_NAMESPACE F(BitAndInt, binaryop) \ F(BitOrInt, binaryop) \ F(BitXorInt, binaryop) \ - F(AddReal, binaryop) \ + F(AddNumber, binaryop) \ F(AddString, binaryop) \ - F(SubReal, binaryop) \ - F(MulReal, binaryop) \ - F(DivReal, binaryop) \ - F(ModReal, binaryop) \ + F(SubNumber, binaryop) \ + F(MulNumber, binaryop) \ + F(DivNumber, binaryop) \ + F(ModNumber, 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(GtNumber, binaryop) \ + F(LtNumber, binaryop) \ + F(GeNumber, binaryop) \ + F(LeNumber, binaryop) \ + F(EqualNumber, binaryop) \ + F(NotEqualNumber, binaryop) \ + F(StrictEqualNumber, binaryop) \ + F(StrictNotEqualNumber, binaryop) \ F(GtString, binaryop) \ F(LtString, binaryop) \ F(GeString, binaryop) \ @@ -147,8 +147,8 @@ QT_BEGIN_NAMESPACE F(NotEqualObject, binaryop) \ F(StrictEqualObject, binaryop) \ F(StrictNotEqualObject, binaryop) \ - F(MathMaxReal, binaryop) \ - F(MathMinReal, binaryop) \ + F(MathMaxNumber, binaryop) \ + F(MathMinNumber, binaryop) \ F(NewString, construct) \ F(NewUrl, construct) \ F(CleanupRegister, cleanup) \ @@ -160,8 +160,7 @@ QT_BEGIN_NAMESPACE F(BranchFalse, branchop) \ F(Branch, branchop) \ F(Block, blockop) \ - /* Speculative property resolution */ \ - F(InitString, initstring) + F(Throw, throwop) #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) # define QML_THREADED_INTERPRETER @@ -192,7 +191,7 @@ class QQmlNotifier; namespace QQmlJS { -union V4Instr { +union Q_AUTOTEST_EXPORT V4Instr { enum Type { FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM) }; @@ -241,6 +240,7 @@ union V4Instr { qint8 output; qint8 reg; quint8 exceptionId; + quint8 valueType; quint32 index; }; @@ -283,10 +283,10 @@ union V4Instr { qint8 reg; }; - struct instr_real_value { + struct instr_number_value { QML_V4_INSTR_HEADER qint8 reg; - qreal value; // XXX Makes the instruction 12 bytes + double value; // XXX Makes the instruction 12 bytes }; struct instr_int_value { @@ -358,6 +358,12 @@ union V4Instr { quint32 block; }; + struct instr_throwop { + QML_V4_INSTR_HEADER + quint8 exceptionId; + quint32 message; + }; + instr_common common; instr_id id; instr_init init; @@ -371,7 +377,7 @@ union V4Instr { instr_copy copy; instr_construct construct; instr_null_value null_value; - instr_real_value real_value; + instr_number_value number_value; instr_int_value int_value; instr_bool_value bool_value; instr_string_value string_value; @@ -383,6 +389,7 @@ union V4Instr { instr_initstring initstring; instr_branchop branchop; instr_blockop blockop; + instr_throwop throwop; }; template<int N> @@ -400,11 +407,11 @@ FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE); #undef QML_V4_INSTR_META_TEMPLATE template<int Instr> -class V4InstrData : public V4InstrMeta<Instr>::DataType +class Q_AUTOTEST_EXPORT V4InstrData : public V4InstrMeta<Instr>::DataType { }; -class Bytecode +class Q_AUTOTEST_EXPORT Bytecode { Q_DISABLE_COPY(Bytecode) diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp index 34245f5bf4..ba0faec80e 100644 --- a/src/qml/qml/v4/qv4ir.cpp +++ b/src/qml/qml/v4/qv4ir.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE namespace QQmlJS { namespace IR { -inline const char *typeName(Type t) +const char *typeName(Type t) { switch (t) { case InvalidType: return "invalid"; @@ -58,15 +58,15 @@ inline const char *typeName(Type t) case NullType: return "null"; case VoidType: return "void"; case StringType: return "string"; - case UrlType: return "url"; - case ColorType: return "color"; + case UrlType: return "QUrl"; + case ColorType: return "QColor"; 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"; + case FloatType: return "float"; + case NumberType: return "number"; default: return "invalid"; } } @@ -91,15 +91,20 @@ IR::Type maxType(IR::Type left, IR::Type right) return IR::StringType; } else if (left == right) return left; - else if (isNumberType(left) && isNumberType(right)) - return qMax(left, right); - else if ((isNumberType(left) && isStringType(right)) || + else if (isNumberType(left) && isNumberType(right)) { + IR::Type ty = qMax(left, right); + return ty == FloatType ? NumberType : ty; // promote floats + } else if ((isNumberType(left) && isStringType(right)) || (isNumberType(right) && isStringType(left))) return IR::StringType; else return IR::InvalidType; } +bool isRealType(IR::Type type) +{ + return type == IR::NumberType || type == IR::FloatType; +} const char *opname(AluOp op) { @@ -233,7 +238,7 @@ void Name::init(Name *base, Type type, const QString *id, Symbol symbol, quint32 builtin = MathMinBuiltinFunction; } else if (id->length() == 7 && *id == QLatin1String("Math.PI")) { builtin = MathPIBuiltinConstant; - this->type = RealType; + this->type = NumberType; } } @@ -267,7 +272,7 @@ Type Unop::typeForOp(AluOp op, Expr *expr) case OpUMinus: case OpUPlus: case OpCompl: - return maxType(expr->type, RealType); + return maxType(expr->type, NumberType); default: break; @@ -309,13 +314,13 @@ Type Binop::typeForOp(AluOp op, Expr *left, Expr *right) case OpAdd: if (left->type == StringType) return StringType; - return RealType; + return NumberType; case OpSub: case OpMul: case OpDiv: case OpMod: - return RealType; + return NumberType; case OpLShift: case OpRShift: @@ -364,7 +369,7 @@ Type Call::typeForFunction(Expr *base) case MathAbsBuiltinFunction: //### type could also be Int if input was Int case MathMaxBuiltinFunction: case MathMinBuiltinFunction: - return RealType; + return NumberType; case MathRoundBultinFunction: case MathFloorBultinFunction: @@ -601,6 +606,12 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) break; } } + } else if (op == OpAdd) { + if (String *s1 = left->asString()) { + if (String *s2 = right->asString()) { + return STRING(function->newString(s1->value.toString() + s2->value)); + } + } } } diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h index 4e9f9faacd..26bd43c406 100644 --- a/src/qml/qml/v4/qv4ir_p.h +++ b/src/qml/qml/v4/qv4ir_p.h @@ -150,10 +150,12 @@ enum Type { FirstNumberType, BoolType = FirstNumberType, IntType, - RealType, - RealNaNType + FloatType, + NumberType }; Type maxType(IR::Type left, IR::Type right); +bool isRealType(IR::Type type); +const char *typeName(IR::Type t); struct ExprVisitor { virtual ~ExprVisitor() {} diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index 453120c6c7..31ed9a5a6a 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -61,8 +61,11 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QM case QMetaType::Int: return IR::IntType; - case QMetaType::QReal: - return IR::RealType; + case QMetaType::Float: + return IR::FloatType; + + case QMetaType::Double: + return IR::NumberType; case QMetaType::QString: return IR::StringType; @@ -542,7 +545,7 @@ bool QV4IRBuilder::visit(AST::NumericLiteral *ast) _expr.format = ExprResult::cx; _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse); } else { - _expr.code = _block->CONST(IR::RealType, ast->value); + _expr.code = _block->CONST(IR::NumberType, ast->value); } return false; } @@ -889,7 +892,14 @@ void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult _expr.format = ExprResult::cx; _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse); } else { - _expr.code = _block->BINOP(IR::binaryOperator(ast->op), left, right); + IR::Expr *e = _block->BINOP(IR::binaryOperator(ast->op), left, right); + if (e->asConst() != 0 || e->asString() != 0) + _expr.code = e; + else { + IR::Temp *t = _block->TEMP(e->type); + _block->MOVE(t, e); + _expr.code = t; + } } } @@ -977,8 +987,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast) 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); + implicitCvt(left, IR::NumberType); + implicitCvt(right, IR::NumberType); binop(ast, left, right); } } break; @@ -998,8 +1008,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast) } } 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); + implicitCvt(left, IR::NumberType); + implicitCvt(right, IR::NumberType); binop(ast, left, right); } else if (left.isValid() && right.isValid()) { binop(ast, left, right); @@ -1086,8 +1096,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast) IR::Type t = maxType(left.type(), right.type()); if (t >= IR::FirstNumberType) { - implicitCvt(left, IR::RealType); - implicitCvt(right, IR::RealType); + implicitCvt(left, IR::NumberType); + implicitCvt(right, IR::NumberType); IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right); _expr.code = _block->TEMP(code->type); diff --git a/src/qml/qml/v4/qv4irbuilder_p.h b/src/qml/qml/v4/qv4irbuilder_p.h index 2b338c0778..e73ec22750 100644 --- a/src/qml/qml/v4/qv4irbuilder_p.h +++ b/src/qml/qml/v4/qv4irbuilder_p.h @@ -95,8 +95,8 @@ protected: case QQmlJS::IR::StringType: case QQmlJS::IR::BoolType: case QQmlJS::IR::IntType: - case QQmlJS::IR::RealType: - case QQmlJS::IR::RealNaNType: + case QQmlJS::IR::FloatType: + case QQmlJS::IR::NumberType: return true; default: diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h index 60e7403786..c1dc39279d 100644 --- a/src/qml/qml/v4/qv4program_p.h +++ b/src/qml/qml/v4/qv4program_p.h @@ -65,7 +65,6 @@ struct QV4Program { quint32 signalTableOffset; quint32 exceptionDataOffset; quint16 subscriptions; - quint16 identifiers; quint16 instructionCount; struct BindingReference { @@ -87,7 +86,8 @@ enum QQmlRegisterType { UndefinedType, NullType, QObjectStarType, - QRealType, + NumberType, + FloatType, IntType, BoolType, diff --git a/src/qml/qml/v8/qjsvalue_p.h b/src/qml/qml/v8/qjsvalue_p.h index acfe958cb6..099d53ee7a 100644 --- a/src/qml/qml/v8/qjsvalue_p.h +++ b/src/qml/qml/v8/qjsvalue_p.h @@ -177,7 +177,7 @@ private: CBool, CNull, CUndefined, - JSValue = 0x2000, // V8 values are equal or higher then this value. + JSValue = 0x2000 // V8 values are equal or higher then this value. // JSPrimitive, // JSObject } m_state; diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp index 4b96679cf3..025854f1ac 100644 --- a/src/qml/qml/v8/qv8bindings.cpp +++ b/src/qml/qml/v8/qv8bindings.cpp @@ -58,7 +58,7 @@ static QQmlJavaScriptExpression::VTable QV8Bindings_Binding_jsvtable = { }; QV8Bindings::Binding::Binding() -: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), target(0), parent(0) +: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), parent(0) { } @@ -85,12 +85,20 @@ void QV8Bindings::Binding::refresh() int QV8Bindings::Binding::propertyIndex() const { - return instruction->property.encodedIndex(); + if (target.hasValue()) return target.constValue()->targetProperty; + else return instruction->property.encodedIndex(); } QObject *QV8Bindings::Binding::object() const { - return target; + if (target.hasValue()) return target.constValue()->target; + else return *target; +} + +void QV8Bindings::Binding::retargetBinding(QObject *t, int i) +{ + target.value().target = t; + target.value().targetProperty = i; } void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags) @@ -127,13 +135,13 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags) trace.event("writing V8 result"); bool needsErrorData = false; - if (!watcher.wasDeleted() && !hasError()) { + if (!watcher.wasDeleted() && !destroyedFlag() && !hasError()) { typedef QQmlPropertyPrivate PP; - needsErrorData = !PP::writeBinding(target, instruction->property, context, this, result, + needsErrorData = !PP::writeBinding(*target, instruction->property, context, this, result, isUndefined, flags); } - if (!watcher.wasDeleted()) { + if (!watcher.wasDeleted() && !destroyedFlag()) { if (needsErrorData) { QUrl url = parent->url(); @@ -156,7 +164,7 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags) ep->dereferenceScarceResources(); } else { - QQmlProperty p = QQmlPropertyPrivate::restore(target, instruction->property, context); + QQmlProperty p = QQmlPropertyPrivate::restore(*target, instruction->property, context); QQmlAbstractBinding::printBindingLoopError(p); } } @@ -177,6 +185,7 @@ void QV8Bindings::Binding::expressionChanged(QQmlJavaScriptExpression *e) void QV8Bindings::Binding::destroy() { setEnabledFlag(false); + setDestroyedFlag(true); removeFromObject(); clear(); clearError(); diff --git a/src/qml/qml/v8/qv8bindings_p.h b/src/qml/qml/v8/qv8bindings_p.h index ad5b2cb8b0..7cc1cc9c21 100644 --- a/src/qml/qml/v8/qv8bindings_p.h +++ b/src/qml/qml/v8/qv8bindings_p.h @@ -53,12 +53,13 @@ // We mean it. // +#include <private/qpointervaluepair_p.h> #include <private/qqmlpropertycache_p.h> #include <private/qqmlinstruction_p.h> #include <private/qqmlexpression_p.h> #include <private/qqmlcompiler_p.h> -#include <private/qqmlbinding_p.h> #include <private/qflagpointer_p.h> +#include <private/qqmlbinding_p.h> QT_BEGIN_HEADER @@ -96,17 +97,26 @@ public: virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags); virtual void update(QQmlPropertyPrivate::WriteFlags flags); virtual void destroy(); - virtual int propertyIndex() const; virtual QObject *object() const; + virtual int propertyIndex() const; + virtual void retargetBinding(QObject *, int); - QObject *target; QV8Bindings *parent; + struct Retarget { + QObject *target; + int targetProperty; + }; + // To save memory, we store flags inside the instruction pointer. - // flag1: enabled - // flag2: updating + // target.flag1: destroyed + // instruction.flag1: enabled + // instruction.flag2: updating + QPointerValuePair<QObject, Retarget> target; QFlagPointer<const QQmlInstruction::instr_assignBinding> instruction; + inline bool destroyedFlag() const { return target.flag(); } + inline void setDestroyedFlag(bool v) { return target.setFlagValue(v); } inline bool enabledFlag() const { return instruction.flag(); } inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); } inline bool updatingFlag() const { return instruction.flag2(); } diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp index 39392b8984..8a98727205 100644 --- a/src/qml/qml/v8/qv8contextwrapper.cpp +++ b/src/qml/qml/v8/qv8contextwrapper.cpp @@ -327,7 +327,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, const QVariant &value = cp->propertyValues.at(propertyIdx); if (value.userType() == qMetaTypeId<QList<QObject*> >()) { - QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*)propertyIdx, + QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), 0, QQmlContextPrivate::context_count, QQmlContextPrivate::context_at); diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 678f9aa3ee..2302d0e369 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -46,7 +46,6 @@ #include "qv8sequencewrapper_p.h" #include "qv8include_p.h" #include "qjsengine_p.h" -#include "../../../3rdparty/javascriptcore/DateMath.h" #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmllist_p.h> @@ -765,23 +764,19 @@ void QV8Engine::setExtensionData(int index, Deletable *data) double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt) { - // from QScriptEngine::DateTimeToMs() if (!dt.isValid()) { return qSNaN(); } - QDateTime utc = dt.toUTC(); - QDate date = utc.date(); - QTime time = utc.time(); - QV8DateConverter::JSC::GregorianDateTime tm; - tm.year = date.year() - 1900; - tm.month = date.month() - 1; - tm.monthDay = date.day(); - tm.weekDay = date.dayOfWeek(); - tm.yearDay = date.dayOfYear(); - tm.hour = time.hour(); - tm.minute = time.minute(); - tm.second = time.second(); - return QV8DateConverter::JSC::gregorianDateTimeToMS(tm, time.msec()); + + return dt.toMSecsSinceEpoch(); +} + +QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate) +{ + if (qIsNaN(jsDate)) + return QDateTime(); + + return QDateTime::fromMSecsSinceEpoch(jsDate); } v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong) @@ -815,24 +810,6 @@ v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, boo } } -QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate) -{ - // from QScriptEngine::MsToDateTime() - if (qIsNaN(jsDate)) - return QDateTime(); - QV8DateConverter::JSC::GregorianDateTime tm; - QV8DateConverter::JSC::msToGregorianDateTime(jsDate, tm); - - // from QScriptEngine::MsFromTime() - int ms = int(::fmod(jsDate, 1000.0)); - if (ms < 0) - ms += int(1000.0); - - QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay), - QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC); - return convertedUTC.toLocalTime(); -} - void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle) { if (handle.IsEmpty()) diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 2350b9dc2c..ce85725642 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -63,7 +63,7 @@ Q_DECLARE_METATYPE(QQmlV8Handle); QT_BEGIN_NAMESPACE -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 // The code in this file does not violate strict aliasing, but GCC thinks it does // so turn off the warnings for us to have a clean build @@ -269,7 +269,7 @@ static v8::Handle<v8::Value> GenericValueGetter(v8::Local<v8::String>, const v8: QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This); QObject *object = resource->object; - if (!object) return v8::Undefined(); + if (QQmlData::wasDeleted(object)) return v8::Undefined(); QQmlPropertyData *property = (QQmlPropertyData *)v8::External::Unwrap(info.Data()); @@ -476,6 +476,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject objectHandle?*objectHandle:engine->newQObject(object), v8::Integer::New(index) }; + Q_ASSERT(argv[0]->IsObject()); return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv); } static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object, @@ -486,10 +487,14 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject v8::Integer::New(index), v8::Context::GetCallingQmlGlobal() }; + Q_ASSERT(argv[0]->IsObject()); return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv); } }; + if (QQmlData::wasDeleted(object)) + return v8::Handle<v8::Value>(); + { // Comparing the hash first actually makes a measurable difference here, at least on x86 quint32 hash = property.hash(); @@ -705,6 +710,9 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH engine->qobjectWrapper()->m_destroyString == property) return true; + if (QQmlData::wasDeleted(object)) + return false; + QQmlPropertyData local; QQmlPropertyData *result = 0; result = QQmlPropertyCache::property(engine->engine(), object, property, local); @@ -735,7 +743,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property, { QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - if (resource->object.isNull()) + if (QQmlData::wasDeleted(resource->object)) return v8::Handle<v8::Value>(); QObject *object = resource->object; @@ -779,7 +787,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property, { QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - if (resource->object.isNull()) + if (QQmlData::wasDeleted(resource->object)) return value; QObject *object = resource->object; @@ -873,7 +881,7 @@ static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, { QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - if (resource->object.isNull()) + if (QQmlData::wasDeleted(resource->object)) return; QObject *object = resource->object; @@ -900,7 +908,7 @@ static void FastValueSetterReadOnly(v8::Local<v8::String> property, v8::Local<v8 { QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - if (resource->object.isNull()) + if (QQmlData::wasDeleted(resource->object)) return; QV8Engine *v8engine = resource->engine; @@ -1080,20 +1088,13 @@ released the handle. */ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object) { - if (!object) + if (QQmlData::wasDeleted(object)) return v8::Null(); - if (QObjectPrivate::get(object)->wasDeleted) - return v8::Null(); - QQmlData *ddata = QQmlData::get(object, true); - if (!ddata) return v8::Undefined(); - if (ddata->isQueuedForDeletion) - return v8::Null(); - if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) { // We own the v8object return v8::Local<v8::Object>::New(ddata->v8object); diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index de492a8ce5..7816c84b79 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -1,5 +1,3 @@ -INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore - include(script.pri) HEADERS += \ @@ -20,7 +18,6 @@ HEADERS += \ $$PWD/qv8include_p.h \ $$PWD/qv8worker_p.h \ $$PWD/qv8bindings_p.h \ - $$PWD/../../../3rdparty/javascriptcore/DateMath.h \ $$PWD/qv8engine_impl_p.h \ $$PWD/qv8domerrors_p.h \ $$PWD/qv8sqlerrors_p.h \ @@ -39,7 +36,6 @@ SOURCES += \ $$PWD/qv8include.cpp \ $$PWD/qv8worker.cpp \ $$PWD/qv8bindings.cpp \ - $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \ $$PWD/qv8domerrors.cpp \ $$PWD/qv8sqlerrors.cpp \ - $$PWD/qqmlbuiltinfunctions.cpp
\ No newline at end of file + $$PWD/qqmlbuiltinfunctions.cpp |