aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp14
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4include.cpp50
-rw-r--r--src/qml/jsruntime/qv4include_p.h9
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp59
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