aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4function.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r--src/qml/jsruntime/qv4function.cpp211
1 files changed, 147 insertions, 64 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 8164bae549..ae36b563e0 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -1,77 +1,82 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qml/qqmlprivate.h"
#include "qv4function_p.h"
-#include "qv4functionobject_p.h"
#include "qv4managed_p.h"
#include "qv4string_p.h"
#include "qv4value_p.h"
#include "qv4engine_p.h"
-#include "qv4lookup_p.h"
#include <private/qv4mm_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4functiontable_p.h>
#include <assembler/MacroAssemblerCodeRef.h>
#include <private/qv4vme_moth_p.h>
#include <private/qqmlglobal_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
QT_BEGIN_NAMESPACE
-using namespace QV4;
+namespace QV4 {
+
+bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int argc,
+ ExecutionContext *context)
+{
+ if (kind != AotCompiled) {
+ return QV4::convertAndCall(
+ context->engine(), thisObject, a, types, argc,
+ [this, context](const Value *thisObject, const Value *argv, int argc) {
+ return call(thisObject, argv, argc, context);
+ });
+ }
-ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
ExecutionEngine *engine = context->engine();
- CppStackFrame frame;
- frame.init(engine, this, argv, argc);
- frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
- thisObject ? *thisObject : Value::undefinedValue(),
- Value::undefinedValue());
+ MetaTypesStackFrame frame;
+ frame.init(this, thisObject, context, a, types, argc);
+ frame.push(engine);
+ Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
+ return !frame.isReturnValueUndefined();
+}
- frame.push();
+static ReturnedValue doCall(
+ QV4::Function *self, const QV4::Value *thisObject, const QV4::Value *argv, int argc,
+ QV4::ExecutionContext *context)
+{
+ ExecutionEngine *engine = context->engine();
+ JSTypesStackFrame frame;
+ frame.init(self, argv, argc);
+ frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
+ thisObject ? *thisObject : Value::undefinedValue());
engine->jsStackTop += frame.requiredJSStackFrameSize();
-
+ frame.push(engine);
ReturnedValue result = Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
+ return result;
+}
- frame.pop();
+ReturnedValue Function::call(
+ const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) {
+ switch (kind) {
+ case AotCompiled:
+ return QV4::convertAndCall(
+ context->engine(), &aotCompiledFunction, thisObject, argv, argc,
+ [this, context](
+ QObject *thisObject, void **a, const QMetaType *types, int argc) {
+ call(thisObject, a, types, argc, context);
+ });
+ case JsTyped:
+ return QV4::coerceAndCall(
+ context->engine(), &jsTypedFunction, compiledFunction, argv, argc,
+ [this, context, thisObject](const Value *argv, int argc) {
+ return doCall(this, thisObject, argv, argc, context);
+ });
+ default:
+ break;
+ }
- return result;
+ return doCall(this, thisObject, argv, argc, context);
}
Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
@@ -86,15 +91,24 @@ void Function::destroy()
delete this;
}
+void Function::mark(MarkStack *ms)
+{
+ if (internalClass)
+ internalClass->mark(ms);
+}
+
+static bool isSpecificType(const CompiledData::ParameterType &type)
+{
+ return type.typeNameIndexOrCommonType()
+ != (type.indexIsCommonType() ? quint32(CompiledData::CommonType::Invalid) : 0);
+}
+
Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
const CompiledData::Function *function,
const QQmlPrivate::AOTCompiledFunction *aotFunction)
- : FunctionData(unit)
+ : FunctionData(engine, unit)
, compiledFunction(function)
, codeData(function->code())
- , jittedCode(nullptr)
- , codeRef(nullptr)
- , aotFunction(aotFunction)
{
Scope scope(engine);
Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
@@ -105,11 +119,59 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
- for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
+ bool enforceJsTypes = !unit->ignoresFunctionSignature();
+
+ for (quint32 i = 0; i < compiledFunction->nFormals; ++i) {
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable);
- internalClass = ic->d();
+ if (enforceJsTypes && !isSpecificType(formalsIndices[i].type))
+ enforceJsTypes = false;
+ }
+ internalClass.set(engine, ic->d());
nFormals = compiledFunction->nFormals;
+
+ if (!enforceJsTypes)
+ return;
+
+ if (aotFunction) {
+ aotCompiledCode = aotFunction->functionPtr;
+ new (&aotCompiledFunction) AOTCompiledFunction;
+ kind = AotCompiled;
+ aotCompiledFunction.types.resize(aotFunction->numArguments + 1);
+ aotFunction->signature(unit, aotCompiledFunction.types.data());
+ return;
+ }
+
+ // If a function has any typed arguments, but an untyped return value, the return value is void.
+ // If it doesn't have any arguments at all and the return value is untyped, the function is
+ // untyped. Users can specifically set the return type to "void" to have it enforced.
+ if (nFormals == 0 && !isSpecificType(compiledFunction->returnType))
+ return;
+
+ QQmlTypeLoader *typeLoader = engine->typeLoader();
+
+ auto findQmlType = [&](const CompiledData::ParameterType &param) {
+ const quint32 type = param.typeNameIndexOrCommonType();
+ if (param.indexIsCommonType()) {
+ return QQmlMetaType::qmlType(QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(
+ QV4::CompiledData::CommonType(type)));
+ }
+
+ if (type == 0 || !typeLoader)
+ return QQmlType();
+
+ const auto &base = unit->baseCompilationUnit();
+ const QQmlType qmltype = QQmlTypePrivate::compositeQmlType(
+ base, typeLoader, base->stringAt(type));
+ return qmltype.typeId().isValid() ? qmltype : QQmlType();
+ };
+
+ new (&jsTypedFunction) JSTypedFunction;
+ kind = JsTyped;
+ jsTypedFunction.types.reserve(nFormals + 1);
+ jsTypedFunction.types.append(findQmlType(compiledFunction->returnType));
+ for (quint16 i = 0; i < nFormals; ++i)
+ jsTypedFunction.types.append(findQmlType(formalsIndices[i].type));
}
Function::~Function()
@@ -118,6 +180,18 @@ Function::~Function()
destroyFunctionTable(this, codeRef);
delete codeRef;
}
+
+ switch (kind) {
+ case JsTyped:
+ jsTypedFunction.~JSTypedFunction();
+ break;
+ case AotCompiled:
+ aotCompiledFunction.~AOTCompiledFunction();
+ break;
+ case JsUntyped:
+ case Eval:
+ break;
+ }
}
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
@@ -125,7 +199,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
QStringList parameterNames;
// Resolve duplicate parameter names:
- for (int i = 0, ei = parameters.count(); i != ei; ++i) {
+ for (int i = 0, ei = parameters.size(); i != ei; ++i) {
const QByteArray &param = parameters.at(i);
int duplicate = -1;
@@ -140,7 +214,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
if (duplicate == -1) {
parameterNames.append(QString::fromUtf8(param));
} else {
- const QString &dup = parameterNames[duplicate];
+ const QString dup = parameterNames[duplicate];
parameterNames.append(dup);
parameterNames[duplicate] =
QString(QChar(0xfffe)) + QString::number(duplicate) + dup;
@@ -148,22 +222,23 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
- internalClass = engine->internalClasses(EngineBase::Class_CallContext);
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
// first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
- internalClass = internalClass->addMember(
+ ic = ic->addMember(
engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]),
Attr_NotConfigurable);
}
- Scope scope(engine);
ScopedString arg(scope);
for (const QString &parameterName : parameterNames) {
arg = engine->newIdentifier(parameterName);
- internalClass = internalClass->addMember(arg->propertyKey(), Attr_NotConfigurable);
+ ic = ic->addMember(arg->propertyKey(), Attr_NotConfigurable);
}
+ internalClass.set(engine, ic->d());
nFormals = parameters.size();
}
@@ -180,7 +255,15 @@ QString Function::prettyName(const Function *function, const void *code)
QQmlSourceLocation Function::sourceLocation() const
{
- return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
+ return QQmlSourceLocation(
+ sourceFile(), compiledFunction->location.line(), compiledFunction->location.column());
}
+FunctionData::FunctionData(EngineBase *engine, ExecutableCompilationUnit *compilationUnit_)
+{
+ compilationUnit.set(engine, compilationUnit_);
+}
+
+} // namespace QV4
+
QT_END_NAMESPACE