diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4include.cpp | 50 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4include_p.h | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 59 |
5 files changed, 91 insertions, 42 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 923d458feb..fe34207ddc 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2048,10 +2048,7 @@ void ExecutionEngine::initQmlGlobalObject() void ExecutionEngine::initializeGlobal() { - QV4::Scope scope(this); - - QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine())); - globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); + createQtObject(); QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions); @@ -2078,6 +2075,15 @@ void ExecutionEngine::initializeGlobal() } } +void ExecutionEngine::createQtObject() +{ + QV4::Scope scope(this); + QtObject *qtObject = new QtObject(this); + QJSEngine::setObjectOwnership(qtObject, QJSEngine::JavaScriptOwnership); + QV4::ScopedObject qt(scope, QV4::QObjectWrapper::wrap(this, qtObject)); + globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); +} + const QSet<QString> &ExecutionEngine::illegalNames() const { return m_illegalNames; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 92bd3a0627..bf24663920 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -689,6 +689,7 @@ public: QV4::ReturnedValue global(); void initQmlGlobalObject(); void initializeGlobal(); + void createQtObject(); void freezeObject(const QV4::Value &value); diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 17512cf4ff..c185894ab3 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -59,20 +59,21 @@ QT_BEGIN_NAMESPACE QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback) - : v4(engine), m_url(url) + : QObject(engine->jsEngine()) + , v4(engine), m_url(url) #if QT_CONFIG(qml_network) , m_redirectCount(0), m_network(nullptr) , m_reply(nullptr) #endif { if (qmlContext) - m_qmlContext.set(engine, *qmlContext); + m_qmlContext.set(v4, *qmlContext); if (callback.as<QV4::FunctionObject>()) - m_callbackFunction.set(engine, callback); + m_callbackFunction.set(v4, callback); m_resultObject.set(v4, resultValue(v4)); #if QT_CONFIG(qml_network) - if (QQmlEngine *qmlEngine = engine->qmlEngine()) { + if (QQmlEngine *qmlEngine = v4->qmlEngine()) { m_network = qmlEngine->networkAccessManager(); QNetworkRequest request; @@ -202,37 +203,40 @@ void QV4Include::finished() /* Documented in qv4engine.cpp */ -QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) +QJSValue QV4Include::method_include(QV4::ExecutionEngine *engine, const QUrl &url, + const QJSValue &callbackFunction) { - QV4::Scope scope(b); - if (!argc) - RETURN_UNDEFINED(); + QQmlRefPointer<QQmlContextData> context = engine->callingQmlContext(); - QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext(); - - if ((!context || !context->isJSContext()) && scope.engine->qmlEngine()) - RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files"))); + if ((!context || !context->isJSContext()) && engine->qmlEngine()) { + return QJSValuePrivate::fromReturnedValue( + engine->throwError( + QString::fromUtf8( + "Qt.include(): Can only be called from JavaScript files"))); + } - QV4::ScopedValue callbackFunction(scope, QV4::Value::undefinedValue()); - if (argc >= 2 && argv[1].as<QV4::FunctionObject>()) - callbackFunction = argv[1]; - QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow())); - if (const QQmlEngine *qmlEngine = scope.engine->qmlEngine()) - url = qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile); + QV4::Scope scope(engine); + QV4::ScopedValue scopedCallbackFunction(scope, QV4::Value::undefinedValue()); + if (auto function = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&callbackFunction)) + scopedCallbackFunction = *function; - QString localFile = QQmlFile::urlToLocalFileOrQrc(url); + const QQmlEngine *qmlEngine = engine->qmlEngine(); + const QUrl intercepted = qmlEngine + ? qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile) + : url; + QString localFile = QQmlFile::urlToLocalFileOrQrc(intercepted); QV4::ScopedValue result(scope); QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext()); if (localFile.isEmpty()) { #if QT_CONFIG(qml_network) - QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction); + QV4Include *i = new QV4Include(url, engine, qmlcontext, scopedCallbackFunction); result = i->result(); #else result = resultValue(scope.engine, NetworkError); - callback(callbackFunction, result); + callback(scopedCallbackFunction, result); #endif } else { QScopedPointer<QV4::Script> script; @@ -255,10 +259,10 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons result = resultValue(scope.engine, NetworkError, error); } - callback(callbackFunction, result); + callback(scopedCallbackFunction, result); } - return result->asReturnedValue(); + return QJSValuePrivate::fromReturnedValue(result->asReturnedValue()); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 9d0a17a5cc..d375abf20a 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -61,7 +61,8 @@ QT_BEGIN_NAMESPACE -class QQmlEngine; +class QJSEngine; +class QJSValue; #if QT_CONFIG(qml_network) class QNetworkAccessManager; #endif @@ -77,13 +78,15 @@ public: Exception = 3 }; - static QV4::ReturnedValue method_include(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QJSValue method_include(QV4::ExecutionEngine *engine, const QUrl &url, + const QJSValue &callbackFunction); private Q_SLOTS: void finished(); private: - QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback); + QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, + const QV4::Value &callback); ~QV4Include(); QV4::ReturnedValue result(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index cabe48dbef..1bf3a01f03 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1554,6 +1554,16 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object, } } +static int numDefinedArguments(QV4::CallData *callArgs) +{ + int numDefinedArguments = callArgs->argc(); + while (numDefinedArguments > 0 + && callArgs->args[numDefinedArguments - 1].type() == QV4::StaticValue::Undefined_Type) { + --numDefinedArguments; + } + return numDefinedArguments; +} + static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs, QMetaObject::Call callType = QMetaObject::InvokeMetaMethod) @@ -1567,6 +1577,35 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ + QLatin1String(unknownTypeError)); } + auto handleTooManyArguments = [&](int expectedArguments) { + const QMetaObject *metaObject = object.metaObject(); + const int indexOfClassInfo = metaObject->indexOfClassInfo("QML.StrictArguments"); + if (indexOfClassInfo != -1 + && QString::fromUtf8(metaObject->classInfo(indexOfClassInfo).value()) + == QStringLiteral("true")) { + engine->throwError(QStringLiteral("Too many arguments")); + return false; + } + + const auto stackTrace = engine->stackTrace(); + if (stackTrace.isEmpty()) { + qWarning().nospace().noquote() + << "When matching arguments for " + << object.className() << "::" << data.name(object.metaObject()) << "():"; + } else { + const StackFrame frame = engine->stackTrace().first(); + qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source + + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line)) + : QString()); + } + + qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1") + .arg(callArgs->argc() - expectedArguments); + return true; + }; + + const int definedArgumentCount = numDefinedArguments(callArgs); + if (data.hasArguments()) { int *args = nullptr; @@ -1588,24 +1627,19 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ return engine->throwError(error); } - if (args[0] < callArgs->argc()) { - Q_ASSERT(!engine->stackTrace().isEmpty()); + if (args[0] < definedArgumentCount) { + if (!handleTooManyArguments(args[0])) + return Encode::undefined(); - const StackFrame frame = engine->stackTrace().first(); - qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source - + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line)) - : QString()); - - qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1") - .arg(callArgs->argc() - args[0]); } return CallMethod(object, data.coreIndex(), returnType, args[0], args + 1, engine, callArgs, callType); } else { + if (definedArgumentCount > 0 && !handleTooManyArguments(0)) + return Encode::undefined(); return CallMethod(object, data.coreIndex(), returnType, 0, nullptr, engine, callArgs, callType); - } } @@ -1626,7 +1660,8 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache, QMetaObject::Call callType = QMetaObject::InvokeMetaMethod) { - int argumentCount = callArgs->argc(); + const int argumentCount = callArgs->argc(); + const int definedArgumentCount = numDefinedArguments(callArgs); QQmlPropertyData best; int bestParameterScore = INT_MAX; @@ -1654,7 +1689,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const if (methodArgumentCount > argumentCount) continue; // We don't have sufficient arguments to call this method - int methodParameterScore = argumentCount - methodArgumentCount; + int methodParameterScore = definedArgumentCount - methodArgumentCount; if (methodParameterScore > bestParameterScore) continue; // We already have a better option |