diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-07-01 08:48:41 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-07-03 13:22:25 +0200 |
commit | 06eaeb0ac8d861cf3e60b11a8fbbabdeef1d6759 (patch) | |
tree | 825fb27485c376d0b83e8dfbcd20c852f2dd525c /src/qml/qml/qqmlboundsignal.cpp | |
parent | b30657647a7f816a2945302b3569b882d7ac6b72 (diff) |
Get rid of the signal expression rewriter
This replaces the entire rewriter with more or less:
expressionToEval = "(function(<named params here>) { " + expr + " } )"
This also fixes crashes at run-time when the signal rewriter was
executed from the loader thread and tried to use a v4 identifier
hash with the same engine that's also in the main thread.
Change-Id: Ib1e4927d330706a593411fbff64ed3da1e23d0e0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml/qqmlboundsignal.cpp')
-rw-r--r-- | src/qml/qml/qqmlboundsignal.cpp | 161 |
1 files changed, 66 insertions, 95 deletions
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index e79aaefe1e..80a06e9761 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -50,7 +50,6 @@ #include "qqml.h" #include "qqmlcontext.h" #include "qqmlglobal_p.h" -#include "qqmlrewrite_p.h" #include <private/qqmlprofilerservice_p.h> #include <private/qv8debugservice_p.h> #include "qqmlinfo.h" @@ -68,45 +67,21 @@ static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { }; QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, - QQmlContextData *ctxt, QObject *scope, const QByteArray &expression, - bool isRewritten, const QString &fileName, quint16 line, quint16 column) - : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), - m_fileName(fileName), - m_line(line), - m_column(column), - m_parameterCountForJS(-1), - m_target(target), - m_index(index), - m_expressionFunctionValid(false), - m_expressionFunctionRewritten(isRewritten), - m_invalidParameterName(false) -{ - init(ctxt, scope); - if (isRewritten) - m_expressionUtf8 = expression; - else - m_expression = QString::fromUtf8(expression); -} - -QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QString &expression, - bool isRewritten, const QString &fileName, quint16 line, quint16 column) + const QString &fileName, quint16 line, quint16 column, + const QString &handlerName) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), m_fileName(fileName), m_line(line), m_column(column), - m_parameterCountForJS(-1), m_target(target), m_index(index), m_expressionFunctionValid(false), - m_expressionFunctionRewritten(isRewritten), m_invalidParameterName(false) { init(ctxt, scope); - if (isRewritten) - m_expressionUtf8 = expression.toUtf8(); - else - m_expression = expression; + m_handlerName = handlerName; + m_expression = expression; } void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) @@ -139,8 +114,6 @@ QString QQmlBoundSignalExpression::expression() const if (m_expressionFunctionValid) { Q_ASSERT (context() && engine()); return m_v8function.value().toQString(); - } else if (!m_expressionUtf8.isEmpty()) { - return QString::fromUtf8(m_expressionUtf8); } else { return m_expression; } @@ -164,47 +137,49 @@ void QQmlBoundSignalExpression::evaluate(void **a) //TODO: look at using the property cache here (as in the compiler) // for further optimization QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - QQmlRewrite::RewriteSignalHandler rewriter(ep->v4engine()); QString expression; - bool ok = true; - - if (m_expressionFunctionRewritten) { - expression = QString::fromUtf8(m_expressionUtf8); - - //if we need parameters, and the rewrite doesn't include them, - //create and insert the parameter string now - if (m_parameterCountForJS == -1 && signal.parameterCount()) { - const QString ¶meters = rewriter.createParameterString(signal.parameterNames(), - ep->v8engine()->illegalNames()); - int index = expression.indexOf(QLatin1Char('('), 1); - Q_ASSERT(index > -1); - expression.insert(index + 1, parameters); - setParameterCountForJS(rewriter.parameterCountForJS()); + expression = QStringLiteral("(function "); + expression += m_handlerName; + expression += QLatin1Char('('); + + QString error; + + bool unnamedParameter = false; + const QV4::IdentifierHash<bool> &illegalNames = ep->v8engine()->illegalNames(); + + const QList<QByteArray> parameters = signal.parameterNames(); + for (int i = 0; i < parameters.count(); ++i) { + if (i > 0) + expression += QLatin1Char(','); + const QByteArray ¶m = parameters.at(i); + if (param.isEmpty()) + unnamedParameter = true; + else if (unnamedParameter) { + error = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter."); + break; + } else if (illegalNames.contains(param)) { + error = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param)); + break; } - - m_expressionUtf8.clear(); - } else { - //expression is still in its original form, so perform a full rewrite - expression = rewriter(m_expression, QString()/*no name hint available*/, &ok, - signal.parameterNames(), - ep->v8engine()->illegalNames()); - setParameterCountForJS(rewriter.parameterCountForJS()); - m_expression.clear(); + expression += QString::fromUtf8(param); } - if (rewriter.hasParameterError()) { - qmlInfo(scopeObject()) << rewriter.parameterError(); + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; m_invalidParameterName = true; ep->dereferenceScarceResources(); return; } - if (ok) { - m_v8function = evalFunction(context(), scopeObject(), expression, - m_fileName, m_line, &m_v8qmlscope); - } + expression += QStringLiteral(") { "); + expression += m_expression; + expression += QStringLiteral(" })"); + m_expression.clear(); + + m_v8function = evalFunction(context(), scopeObject(), expression, + m_fileName, m_line, &m_v8qmlscope); if (m_v8function.isEmpty() || m_v8function.value().isNull()) { ep->dereferenceScarceResources(); @@ -214,42 +189,38 @@ void QQmlBoundSignalExpression::evaluate(void **a) m_expressionFunctionValid = true; } - if (!hasParameterInfo()) { - QQmlJavaScriptExpression::evaluate(context(), m_v8function.value(), 0); - } else { - QV8Engine *engine = ep->v8engine(); - QVarLengthArray<int, 9> dummy; - //TODO: lookup via signal index rather than method index as an optimization - int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); - int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0); - int argCount = argsTypes ? m_parameterCountForJS : 0; - - QVarLengthArray<QV4::Value, 9> args(argCount); - - for (int ii = 0; ii < argCount; ++ii) { - int type = argsTypes[ii + 1]; - //### ideally we would use metaTypeToJS, however it currently gives different results - // for several cases (such as QVariant type and QObject-derived types) - //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); - if (type == QMetaType::QVariant) { - args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1])); - } else if (type == QMetaType::Int) { - //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise - args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); - } else if (type == qMetaTypeId<QQmlV4Handle>()) { - args[ii] = reinterpret_cast<QQmlV4Handle *>(a[ii + 1])->toValue(); - } else if (ep->isQObject(type)) { - if (!*reinterpret_cast<void* const *>(a[ii + 1])) - args[ii] = QV4::Value::nullValue(); - else - args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); - } else { - args[ii] = engine->fromVariant(QVariant(type, a[ii + 1])); - } + QV8Engine *engine = ep->v8engine(); + QVarLengthArray<int, 9> dummy; + //TODO: lookup via signal index rather than method index as an optimization + int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); + int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0); + int argCount = argsTypes ? *argsTypes : 0; + + QVarLengthArray<QV4::Value, 9> args(argCount); + + for (int ii = 0; ii < argCount; ++ii) { + int type = argsTypes[ii + 1]; + //### ideally we would use metaTypeToJS, however it currently gives different results + // for several cases (such as QVariant type and QObject-derived types) + //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); + if (type == QMetaType::QVariant) { + args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1])); + } else if (type == QMetaType::Int) { + //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise + args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); + } else if (type == qMetaTypeId<QQmlV4Handle>()) { + args[ii] = reinterpret_cast<QQmlV4Handle *>(a[ii + 1])->toValue(); + } else if (ep->isQObject(type)) { + if (!*reinterpret_cast<void* const *>(a[ii + 1])) + args[ii] = QV4::Value::nullValue(); + else + args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); + } else { + args[ii] = engine->fromVariant(QVariant(type, a[ii + 1])); } - - QQmlJavaScriptExpression::evaluate(context(), m_v8function.value(), argCount, args.data(), 0); } + + QQmlJavaScriptExpression::evaluate(context(), m_v8function.value(), argCount, args.data(), 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } |