1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qml/qqmlprivate.h"
5#include "qv4function_p.h"
6#include "qv4managed_p.h"
7#include "qv4string_p.h"
8#include "qv4value_p.h"
9#include "qv4engine_p.h"
10#include <private/qv4mm_p.h>
11#include <private/qv4identifiertable_p.h>
12#include <private/qv4functiontable_p.h>
13#include <assembler/MacroAssemblerCodeRef.h>
14#include <private/qv4vme_moth_p.h>
15#include <private/qqmlglobal_p.h>
16#include <private/qv4jscall_p.h>
17#include <private/qqmlpropertycachecreator_p.h>
18
19QT_BEGIN_NAMESPACE
20
21namespace QV4 {
22
23bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int argc,
24 ExecutionContext *context)
25{
26 if (kind != AotCompiled) {
27 return QV4::convertAndCall(
28 engine: context->engine(), thisObject, a, types, argc,
29 call: [this, context](const Value *thisObject, const Value *argv, int argc) {
30 return call(thisObject, argv, argc, context);
31 });
32 }
33
34 ExecutionEngine *engine = context->engine();
35 MetaTypesStackFrame frame;
36 frame.init(v4Function: this, thisObject, context, returnAndArgs: a, metaTypes: types, argc);
37 frame.push(engine);
38 Moth::VME::exec(frame: &frame, engine);
39 frame.pop(engine);
40 return !frame.isReturnValueUndefined();
41}
42
43static ReturnedValue doCall(
44 QV4::Function *self, const QV4::Value *thisObject, const QV4::Value *argv, int argc,
45 QV4::ExecutionContext *context)
46{
47 ExecutionEngine *engine = context->engine();
48 JSTypesStackFrame frame;
49 frame.init(v4Function: self, argv, argc);
50 frame.setupJSFrame(stackSpace: engine->jsStackTop, function: Value::undefinedValue(), scope: context->d(),
51 thisObject: thisObject ? *thisObject : Value::undefinedValue());
52 engine->jsStackTop += frame.requiredJSStackFrameSize();
53 frame.push(engine);
54 ReturnedValue result = Moth::VME::exec(frame: &frame, engine);
55 frame.pop(engine);
56 return result;
57}
58
59ReturnedValue Function::call(
60 const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) {
61 switch (kind) {
62 case AotCompiled:
63 return QV4::convertAndCall(
64 engine: context->engine(), aotFunction: aotCompiledFunction, thisObject, argv, argc,
65 call: [this, context](
66 QObject *thisObject, void **a, const QMetaType *types, int argc) {
67 call(thisObject, a, types, argc, context);
68 });
69 case JsTyped:
70 return QV4::coerceAndCall(
71 engine: context->engine(), typedFunction: aotCompiledFunction, thisObject, argv, argc,
72 call: [this, context](const Value *thisObject, const Value *argv, int argc) {
73 return doCall(self: this, thisObject, argv, argc, context);
74 });
75 default:
76 break;
77 }
78
79 return doCall(self: this, thisObject, argv, argc, context);
80}
81
82Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
83 const CompiledData::Function *function,
84 const QQmlPrivate::AOTCompiledFunction *aotFunction)
85{
86 return new Function(engine, unit, function, aotFunction);
87}
88
89void Function::destroy()
90{
91 delete this;
92}
93
94Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
95 const CompiledData::Function *function,
96 const QQmlPrivate::AOTCompiledFunction *aotFunction)
97 : FunctionData(unit)
98 , compiledFunction(function)
99 , codeData(function->code())
100 , jittedCode(nullptr)
101 , codeRef(nullptr)
102 , aotCompiledFunction(aotFunction)
103 , kind(aotFunction ? AotCompiled : JsUntyped)
104{
105 Scope scope(engine);
106 Scoped<InternalClass> ic(scope, engine->internalClasses(icType: EngineBase::Class_CallContext));
107
108 // first locals
109 const quint32_le *localsIndices = compiledFunction->localsTable();
110 for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
111 ic = ic->addMember(identifier: engine->identifierTable->asPropertyKey(str: compilationUnit->runtimeStrings[localsIndices[i]]), data: Attr_NotConfigurable);
112
113 const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
114 const bool enforcesSignature = !aotFunction && unit->enforcesFunctionSignature();
115 bool hasTypes = false;
116 for (quint32 i = 0; i < compiledFunction->nFormals; ++i) {
117 ic = ic->addMember(identifier: engine->identifierTable->asPropertyKey(str: compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), data: Attr_NotConfigurable);
118 if (enforcesSignature
119 && !hasTypes
120 && formalsIndices[i].type.typeNameIndexOrCommonType()
121 != quint32(QV4::CompiledData::CommonType::Invalid)) {
122 hasTypes = true;
123 }
124 }
125 internalClass = ic->d();
126
127 nFormals = compiledFunction->nFormals;
128
129 if (!enforcesSignature)
130 return;
131
132 if (!hasTypes
133 && compiledFunction->returnType.typeNameIndexOrCommonType()
134 == quint32(QV4::CompiledData::CommonType::Invalid)) {
135 return;
136 }
137
138 QQmlPrivate::AOTCompiledFunction *synthesized = new QQmlPrivate::AOTCompiledFunction;
139 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(e: engine->qmlEngine());
140
141 auto findMetaType = [&](const CompiledData::ParameterType &param) {
142 const quint32 type = param.typeNameIndexOrCommonType();
143 if (param.indexIsCommonType()) {
144 if (param.isList()) {
145 return QQmlPropertyCacheCreatorBase::listTypeForPropertyType(
146 type: QV4::CompiledData::CommonType(type));
147 }
148 return QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(
149 type: QV4::CompiledData::CommonType(type));
150 }
151
152 if (type == 0)
153 return QMetaType();
154
155 const QQmlType qmltype = unit->typeNameCache->query(key: unit->stringAt(index: type)).type;
156 if (!qmltype.isValid())
157 return QMetaType();
158
159 const QMetaType metaType = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
160 if (metaType.isValid())
161 return metaType;
162
163 if (!qmltype.isComposite()) {
164 if (!qmltype.isInlineComponentType())
165 return QMetaType();
166 const CompositeMetaTypeIds typeIds = unit->typeIdsForComponent(inlineComponentName: qmltype.elementName());
167 return param.isList() ? typeIds.listId : typeIds.id;
168 }
169
170 const CompositeMetaTypeIds typeIds = enginePrivate->typeLoader.getType(
171 unNormalizedUrl: qmltype.sourceUrl())->compilationUnit()->typeIds;
172 return param.isList() ? typeIds.listId : typeIds.id;
173 };
174
175 for (quint16 i = 0; i < nFormals; ++i)
176 synthesized->argumentTypes.append(t: findMetaType(formalsIndices[i].type));
177
178 synthesized->returnType = findMetaType(compiledFunction->returnType);
179 aotCompiledFunction = synthesized;
180 kind = JsTyped;
181}
182
183Function::~Function()
184{
185 if (codeRef) {
186 destroyFunctionTable(function: this, codeRef);
187 delete codeRef;
188 }
189 if (kind == JsTyped)
190 delete aotCompiledFunction;
191}
192
193void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
194{
195 QStringList parameterNames;
196
197 // Resolve duplicate parameter names:
198 for (int i = 0, ei = parameters.size(); i != ei; ++i) {
199 const QByteArray &param = parameters.at(i);
200 int duplicate = -1;
201
202 for (int j = i - 1; j >= 0; --j) {
203 const QByteArray &prevParam = parameters.at(i: j);
204 if (param == prevParam) {
205 duplicate = j;
206 break;
207 }
208 }
209
210 if (duplicate == -1) {
211 parameterNames.append(t: QString::fromUtf8(ba: param));
212 } else {
213 const QString dup = parameterNames[duplicate];
214 parameterNames.append(t: dup);
215 parameterNames[duplicate] =
216 QString(QChar(0xfffe)) + QString::number(duplicate) + dup;
217 }
218
219 }
220
221 internalClass = engine->internalClasses(icType: EngineBase::Class_CallContext);
222
223 // first locals
224 const quint32_le *localsIndices = compiledFunction->localsTable();
225 for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
226 internalClass = internalClass->addMember(
227 identifier: engine->identifierTable->asPropertyKey(str: compilationUnit->runtimeStrings[localsIndices[i]]),
228 data: Attr_NotConfigurable);
229 }
230
231 Scope scope(engine);
232 ScopedString arg(scope);
233 for (const QString &parameterName : parameterNames) {
234 arg = engine->newIdentifier(text: parameterName);
235 internalClass = internalClass->addMember(identifier: arg->propertyKey(), data: Attr_NotConfigurable);
236 }
237 nFormals = parameters.size();
238}
239
240QString Function::prettyName(const Function *function, const void *code)
241{
242 QString prettyName = function ? function->name()->toQString() : QString();
243 if (prettyName.isEmpty()) {
244 prettyName = QString::number(reinterpret_cast<quintptr>(code), base: 16);
245 prettyName.prepend(s: QLatin1String("QV4::Function(0x"));
246 prettyName.append(c: QLatin1Char(')'));
247 }
248 return prettyName;
249}
250
251QQmlSourceLocation Function::sourceLocation() const
252{
253 return QQmlSourceLocation(
254 sourceFile(), compiledFunction->location.line(), compiledFunction->location.column());
255}
256
257} // namespace QV4
258
259QT_END_NAMESPACE
260

source code of qtdeclarative/src/qml/jsruntime/qv4function.cpp