Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4jscall_p.h
Go to the documentation of this file.
1// Copyright (C) 2017 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#ifndef QV4JSCALL_H
4#define QV4JSCALL_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qqmlengine_p.h>
18#include <private/qqmllistwrapper_p.h>
19#include <private/qqmlvaluetype_p.h>
20#include <private/qqmlvaluetypewrapper_p.h>
21#include <private/qv4alloca_p.h>
22#include <private/qv4context_p.h>
23#include <private/qv4dateobject_p.h>
24#include <private/qv4function_p.h>
25#include <private/qv4functionobject_p.h>
26#include <private/qv4object_p.h>
27#include <private/qv4qobjectwrapper_p.h>
28#include <private/qv4regexpobject_p.h>
29#include <private/qv4scopedvalue_p.h>
30#include <private/qv4stackframe_p.h>
31#include <private/qv4urlobject_p.h>
32#include <private/qv4variantobject_p.h>
33
34#if QT_CONFIG(regularexpression)
35#include <QtCore/qregularexpression.h>
36#endif
37
39
40namespace QV4 {
41
42template<typename Args>
43CallData *callDatafromJS(const Scope &scope, const Args *args, const FunctionObject *f = nullptr)
44{
45 int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + args->argc;
46 CallData *ptr = reinterpret_cast<CallData *>(scope.alloc<Scope::Uninitialized>(size));
47 ptr->function = Encode::undefined();
48 ptr->context = Encode::undefined();
49 ptr->accumulator = Encode::undefined();
50 ptr->thisObject = args->thisObject ? args->thisObject->asReturnedValue() : Encode::undefined();
51 ptr->newTarget = Encode::undefined();
52 ptr->setArgc(args->argc);
53 if (args->argc)
54 memcpy(ptr->args, args->args, args->argc*sizeof(Value));
55 if (f)
56 ptr->function = f->asReturnedValue();
57 return ptr;
58}
59
61{
62 JSCallArguments(const Scope &scope, int argc = 0)
63 : thisObject(scope.alloc()), args(scope.alloc(argc)), argc(argc)
64 {
65 }
66
67 CallData *callData(const Scope &scope, const FunctionObject *f = nullptr) const
68 {
69 return callDatafromJS(scope, this, f);
70 }
71
74 const int argc;
75};
76
78{
79 JSCallData(const Value *thisObject, const Value *argv, int argc)
81 {
82 }
83
86 {
87 }
88
89 CallData *callData(const Scope &scope, const FunctionObject *f = nullptr) const
90 {
91 return callDatafromJS(scope, this, f);
92 }
93
95 const Value *args;
96 const int argc;
97};
98
99inline
101{
102 return callAsConstructor(data.args, data.argc, this);
103}
104
105inline
107{
108 return call(data.thisObject, data.args, data.argc);
109}
110
112 void **args, const QMetaType *types);
113
114template<typename Callable>
117 const Value *thisObject, const Value *argv, int argc, Callable call)
118{
119 const qsizetype numFunctionArguments = aotFunction->argumentTypes.size();
120 Q_ALLOCA_VAR(void *, values, (numFunctionArguments + 1) * sizeof(void *));
121 Q_ALLOCA_VAR(QMetaType, types, (numFunctionArguments + 1) * sizeof(QMetaType));
122
123 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
124 const QMetaType argumentType = aotFunction->argumentTypes[i];
125 types[i + 1] = argumentType;
126 if (const qsizetype argumentSize = argumentType.sizeOf()) {
127 Q_ALLOCA_VAR(void, argument, argumentSize);
128 argumentType.construct(argument);
129 if (i < argc)
130 ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument);
131 values[i + 1] = argument;
132 } else {
133 values[i + 1] = nullptr;
134 }
135 }
136
137 Q_ALLOCA_DECLARE(void, returnValue);
138 types[0] = aotFunction->returnType;
139 if (const qsizetype returnSize = types[0].sizeOf()) {
140 Q_ALLOCA_ASSIGN(void, returnValue, returnSize);
141 values[0] = returnValue;
142 } else {
143 values[0] = nullptr;
144 }
145
146 if (const QV4::QObjectWrapper *cppThisObject = thisObject->as<QV4::QObjectWrapper>())
147 call(cppThisObject->object(), values, types, argc);
148 else
149 call(nullptr, values, types, argc);
150
152 if (values[0]) {
153 result = engine->metaTypeToJS(types[0], values[0]);
154 types[0].destruct(values[0]);
155 } else {
157 }
158
159 for (qsizetype i = 1, end = numFunctionArguments + 1; i < end; ++i)
160 types[i].destruct(values[i]);
161
162 return result;
163}
164
165template<typename Callable>
167 void **a, const QMetaType *types, int argc, Callable call)
168{
169 Scope scope(engine);
170 QV4::JSCallArguments jsCallData(scope, argc);
171
172 for (int ii = 0; ii < argc; ++ii)
173 jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
174
175 ScopedObject jsThisObject(scope);
176 if (thisObject) {
177 // The result of wrap() can only be null, undefined, or an object.
178 jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject);
179 if (!jsThisObject)
180 jsThisObject = engine->globalObject;
181 } else {
182 jsThisObject = engine->globalObject;
183 }
184
185 ScopedValue jsResult(scope, call(jsThisObject, jsCallData.args, argc));
186 void *result = a[0];
187 if (!result)
188 return !jsResult->isUndefined();
189
190 const QMetaType resultType = types[0];
191 if (scope.hasException()) {
192 // Clear the return value
193 resultType.construct(result);
194 } else {
195 // When the return type is QVariant, JS objects are to be returned as
196 // QJSValue wrapped in QVariant. metaTypeFromJS unwraps them, unfortunately.
197 if (resultType == QMetaType::fromType<QVariant>()) {
199 } else {
200 resultType.construct(result);
201 ExecutionEngine::metaTypeFromJS(jsResult, resultType, result);
202 }
203 }
204 return !jsResult->isUndefined();
205}
206
207inline ReturnedValue coerce(
208 ExecutionEngine *engine, const Value &value, const QQmlType &qmlType, bool isList);
209
210inline QObject *coerceQObject(const Value &value, const QQmlType &qmlType)
211{
212 QObject *o;
214 o = wrapper->object();
215 else if (const QV4::QQmlTypeWrapper *wrapper = value.as<QQmlTypeWrapper>())
216 o = wrapper->object();
217 else
218 return nullptr;
219
220 return (o && qmlobject_can_qml_cast(o, qmlType)) ? o : nullptr;
221}
222
224{
228
229Q_QML_PRIVATE_EXPORT void warnAboutCoercionToVoid(
230 ExecutionEngine *engine, const Value &value, CoercionProblem problem);
231
233 ExecutionEngine *engine, const Value &value, const QQmlType &qmlType)
234{
235 QMetaType type = qmlType.qListTypeId();
236 const auto metaSequence = [&]() {
237 // TODO: We should really add the metasequence to the same QQmlType that holds
238 // all the other type information. Then we can get rid of the extra
239 // QQmlMetaType::qmlListType() here.
240 return qmlType.isSequentialContainer()
241 ? qmlType.listMetaSequence()
243 };
244
245 if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
246 if (sequence->d()->listType() == type)
247 return value.asReturnedValue();
248 }
249
250 if (const QmlListWrapper *list = value.as<QmlListWrapper>()) {
251 if (list->d()->propertyType() == type)
252 return value.asReturnedValue();
253 }
254
255 QMetaType listValueType = qmlType.typeId();
256 if (!listValueType.isValid()) {
258 return value.asReturnedValue();
259 }
260
261 QV4::Scope scope(engine);
262
264 if (!array) {
265 return (listValueType.flags() & QMetaType::PointerToQObject)
266 ? QmlListWrapper::create(engine, listValueType)
267 : SequencePrototype::fromData(engine, type, metaSequence(), nullptr);
268 }
269
270 if (listValueType.flags() & QMetaType::PointerToQObject) {
271 QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, listValueType));
272 QQmlListProperty<QObject> *listProperty = newList->d()->property();
273
274 const qsizetype length = array->getLength();
275 qsizetype i = 0;
276 for (; i < length; ++i) {
277 ScopedValue v(scope, array->get(i));
278 listProperty->append(listProperty, coerceQObject(v, qmlType));
279 }
280
281 return newList->asReturnedValue();
282 }
283
284 QV4::Scoped<Sequence> sequence(
285 scope, SequencePrototype::fromData(engine, type, metaSequence(), nullptr));
286 const qsizetype length = array->getLength();
287 for (qsizetype i = 0; i < length; ++i)
288 sequence->containerPutIndexed(i, array->get(i));
289 return sequence->asReturnedValue();
290}
291
293 ExecutionEngine *engine, const Value &value, const QQmlType &qmlType, bool isList)
294{
295 // These are all the named non-list, non-QObject builtins. Only those need special handling.
296 // Some of them may be wrapped in VariantObject because that is how they are stored in VME
297 // properties.
298 if (isList)
299 return coerceListType(engine, value, qmlType);
300
301 const QMetaType metaType = qmlType.typeId();
302 if (!metaType.isValid()) {
303 if (!value.isUndefined())
305 return value.asReturnedValue();
306 }
307
308 switch (metaType.id()) {
309 case QMetaType::Void:
310 return Encode::undefined();
312 return value.asReturnedValue();
313 case QMetaType::Int:
314 return Encode(value.toInt32());
315 case QMetaType::Double:
316 return value.convertedToNumber();
317 case QMetaType::QString:
318 return value.toString(engine)->asReturnedValue();
319 case QMetaType::Bool:
320 return Encode(value.toBoolean());
321 case QMetaType::QDateTime:
322 if (value.as<DateObject>())
323 return value.asReturnedValue();
324 if (const VariantObject *varObject = value.as<VariantObject>()) {
325 const QVariant &var = varObject->d()->data();
326 switch (var.metaType().id()) {
327 case QMetaType::QDateTime:
328 return engine->newDateObject(var.value<QDateTime>())->asReturnedValue();
329 case QMetaType::QTime:
330 return engine->newDateObject(var.value<QTime>(), nullptr, -1, 0)->asReturnedValue();
331 case QMetaType::QDate:
332 return engine->newDateObject(var.value<QDate>(), nullptr, -1, 0)->asReturnedValue();
333 default:
334 break;
335 }
336 }
337 return engine->newDateObject(QDateTime())->asReturnedValue();
338 case QMetaType::QUrl:
339 if (value.as<UrlObject>())
340 return value.asReturnedValue();
341 if (const VariantObject *varObject = value.as<VariantObject>()) {
342 const QVariant &var = varObject->d()->data();
343 return var.metaType() == QMetaType::fromType<QUrl>()
344 ? engine->newUrlObject(var.value<QUrl>())->asReturnedValue()
345 : engine->newUrlObject()->asReturnedValue();
346 }
347 // Since URL properties are stored as string, we need to support the string conversion here.
348 if (const String *string = value.stringValue())
349 return engine->newUrlObject(QUrl(string->toQString()))->asReturnedValue();
350 return engine->newUrlObject()->asReturnedValue();
351#if QT_CONFIG(regularexpression)
352 case QMetaType::QRegularExpression:
353 if (value.as<RegExpObject>())
354 return value.asReturnedValue();
355 if (const VariantObject *varObject = value.as<VariantObject>()) {
356 const QVariant &var = varObject->d()->data();
357 if (var.metaType() == QMetaType::fromType<QRegularExpression>())
358 return engine->newRegExpObject(var.value<QRegularExpression>())->asReturnedValue();
359 }
360 return engine->newRegExpObject(QString(), 0)->asReturnedValue();
361#endif
362 default:
363 break;
364 }
365
366 if (metaType.flags() & QMetaType::PointerToQObject) {
367 return coerceQObject(value, qmlType)
368 ? value.asReturnedValue()
369 : Encode::null();
370 }
371
373 if (wrapper->type() == metaType)
374 return value.asReturnedValue();
375 }
376
378 Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
379 nullptr, metaType, QQmlMetaType::metaObjectForValueType(qmlType),
380 nullptr, -1, Heap::ReferenceObject::NoFlag);
381 Q_ASSERT(!wrapper->gadgetPtr());
382 wrapper->setGadgetPtr(target);
383 return wrapper->asReturnedValue();
384 }
385
386 return Encode::undefined();
387}
388
389template<typename Callable>
392 const Function::JSTypedFunction *typedFunction, const CompiledData::Function *compiledFunction,
393 const Value *thisObject, const Value *argv, int argc, Callable call)
394{
395 Scope scope(engine);
396
397 QV4::JSCallArguments jsCallData(scope, typedFunction->argumentTypes.size());
398 const CompiledData::Parameter *formals = compiledFunction->formalsTable();
399 for (qsizetype i = 0; i < jsCallData.argc; ++i) {
400 jsCallData.args[i] = coerce(
401 engine, i < argc ? argv[i] : Encode::undefined(),
402 typedFunction->argumentTypes[i], formals[i].type.isList());
403 }
404
405 ScopedValue result(scope, call(thisObject, jsCallData.args, jsCallData.argc));
406 return coerce(engine, result, typedFunction->returnType, compiledFunction->returnType.isList());
407}
408
409} // namespace QV4
410
412
413#endif // QV4JSCALL_H
\inmodule QtCore\reentrant
Definition qdatetime.h:257
\inmodule QtCore \reentrant
Definition qdatetime.h:27
QJSValue globalObject() const
Returns this engine's Global Object.
qsizetype size() const noexcept
Definition qlist.h:386
\inmodule QtCore
Definition qmetatype.h:320
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
constexpr qsizetype sizeOf() const
Definition qmetatype.h:2618
bool isValid() const
int id(int=0) const
Definition qmetatype.h:454
@ PointerToQObject
Definition qmetatype.h:385
void * construct(void *where, const void *copy=nullptr) const
friend class QVariant
Definition qmetatype.h:775
\inmodule QtCore
Definition qobject.h:90
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
AppendFunction append
Definition qqmllist.h:84
static QQmlType qmlListType(QMetaType metaType)
static const QMetaObject * metaObjectForValueType(QMetaType type)
QMetaType typeId() const
Definition qqmltype.cpp:643
bool isSequentialContainer() const
Definition qqmltype.cpp:638
QMetaSequence listMetaSequence() const
Definition qqmltype.cpp:653
QMetaType qListTypeId() const
Definition qqmltype.cpp:648
static Q_QML_PRIVATE_EXPORT void * heapCreateValueType(const QQmlType &targetType, const QV4::Value &source)
\inmodule QtCore \reentrant
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore \reentrant
Definition qdatetime.h:189
\inmodule QtCore
Definition qurl.h:94
\inmodule QtCore
Definition qvariant.h:64
T value() const &
Definition qvariant.h:511
Private d
Definition qvariant.h:665
QMetaType metaType() const
Combined button and popup list for selecting options.
\qmltype Particle \inqmlmodule QtQuick.Particles
ReturnedValue coerceListType(ExecutionEngine *engine, const Value &value, const QQmlType &qmlType)
ReturnedValue convertAndCall(ExecutionEngine *engine, const QQmlPrivate::AOTCompiledFunction *aotFunction, const Value *thisObject, const Value *argv, int argc, Callable call)
CoercionProblem
@ InvalidListType
@ InsufficientAnnotation
CallData * callDatafromJS(const Scope &scope, const Args *args, const FunctionObject *f=nullptr)
Definition qv4jscall_p.h:43
ReturnedValue coerce(ExecutionEngine *engine, const Value &value, const QQmlType &qmlType, bool isList)
quint64 ReturnedValue
ReturnedValue coerceAndCall(ExecutionEngine *engine, const Function::JSTypedFunction *typedFunction, const CompiledData::Function *compiledFunction, const Value *thisObject, const Value *argv, int argc, Callable call)
void populateJSCallArguments(ExecutionEngine *v4, JSCallArguments &jsCall, int argc, void **args, const QMetaType *types)
Definition qv4jscall.cpp:18
QObject * coerceQObject(const Value &value, const QQmlType &qmlType)
Q_QML_PRIVATE_EXPORT void warnAboutCoercionToVoid(ExecutionEngine *engine, const Value &value, CoercionProblem problem)
Definition qv4jscall.cpp:25
#define Q_IMPLICIT
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static ControlElement< T > * ptr(QWidget *widget)
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLfloat GLfloat f
GLenum type
GLenum target
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum array
GLuint64EXT * result
[6]
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
ptrdiff_t qsizetype
Definition qtypes.h:70
#define Q_ALLOCA_VAR(type, name, size)
Definition qv4alloca_p.h:36
#define Q_ALLOCA_ASSIGN(type, name, size)
Definition qv4alloca_p.h:66
#define Q_ALLOCA_DECLARE(type, name)
Definition qv4alloca_p.h:62
QList< int > list
[14]
QDBusArgument argument
QJSValueList args
QJSEngine engine
[0]
QList< QMetaType > argumentTypes
const Parameter * formalsTable() const
static constexpr ReturnedValue undefined()
static constexpr ReturnedValue null()
static bool metaTypeFromJS(const Value &value, QMetaType type, void *data)
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
ReturnedValue call(const JSCallData &data) const
ReturnedValue callAsConstructor(const JSCallData &data) const
QList< QQmlType > argumentTypes
JSCallArguments(const Scope &scope, int argc=0)
Definition qv4jscall_p.h:62
CallData * callData(const Scope &scope, const FunctionObject *f=nullptr) const
Definition qv4jscall_p.h:67
const int argc
Definition qv4jscall_p.h:96
CallData * callData(const Scope &scope, const FunctionObject *f=nullptr) const
Definition qv4jscall_p.h:89
const Value * thisObject
Definition qv4jscall_p.h:94
JSCallData(const Value *thisObject, const Value *argv, int argc)
Definition qv4jscall_p.h:79
const Value * args
Definition qv4jscall_p.h:95
Q_IMPLICIT JSCallData(const JSCallArguments &args)
Definition qv4jscall_p.h:84
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object)
static V4_NEEDS_DESTROY ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, QMetaType propType)
Value * alloc(qint64 nValues) const =delete
bool hasException() const
QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const
static ReturnedValue fromData(QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data)
bool isUndefined() const
QML_NEARLY_ALWAYS_INLINE String * stringValue() const
Definition qv4value_p.h:55
const T * as() const
Definition qv4value_p.h:132
uchar data[MaxInternalSize]
Definition qvariant.h:111
void wrapper()