diff options
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 211 |
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 ¶m) { + 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> ¶meters) @@ -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 ¶m = 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 ¶meterName : 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 |