43 int size =
int(offsetof(QV4::CallData, args)/
sizeof(QV4::Value)) + args->argc;
45 ptr->function = Encode::undefined();
46 ptr->context = Encode::undefined();
47 ptr->accumulator = Encode::undefined();
48 ptr->thisObject = args->thisObject ? args->thisObject->asReturnedValue() : Encode::undefined();
49 ptr->newTarget = Encode::undefined();
50 ptr->setArgc(args->argc);
52 memcpy(ptr->args, args->args, args->argc*
sizeof(Value));
54 ptr->function = f->asReturnedValue();
154 ExecutionEngine *engine,
const QMetaType *types,
int numTypes,
155 const Value *argv,
int argc, Callable &&call,
156 ConstructReturnValue &&constructReturnValue = defaultConstructReturnValue,
157 ConvertReturnValue &&convertReturnValue = defaultConvertReturnValue,
158 ConversionErrorHandler &&errorHandler = defaultConversionErrorHandler)
161 Q_ALLOCA_VAR(
void *, values, numTypes *
sizeof(
void *));
163 for (qsizetype i = 1; i < numTypes; ++i) {
164 const QMetaType argumentType = types[i];
165 if (
const qsizetype argumentSize = argumentType.sizeOf()) {
166 Q_ALLOCA_VAR(
void, argument, argumentSize);
167 const int argIndex = i - 1;
168 if (argumentType.flags() & QMetaType::NeedsConstruction)
169 argumentType.construct(argument);
172 || !ExecutionEngine::metaTypeFromJS(argv[argIndex], argumentType, argument)) {
173 if (!errorHandler(argumentType, argument, argIndex)) {
174 for (qsizetype j = 1; j < i; ++j) {
175 if (types[j].flags() & QMetaType::NeedsDestruction)
176 types[j].destruct(values[j]);
178 return Encode::undefined();
182 values[i] = argument;
188 Q_ALLOCA_DECLARE(
void, returnValue);
189 if (
const qsizetype returnSize = types[0].sizeOf()) {
190 Q_ALLOCA_ASSIGN(
void, returnValue, returnSize);
191 constructReturnValue(types[0], returnValue);
192 values[0] = returnValue;
197 call(values, types, argc);
199 const ReturnedValue result = values[0]
200 ? convertReturnValue(engine, types[0], returnValue)
201 : Encode::undefined();
203 for (qsizetype i = 1, end = numTypes; i <
end; ++i) {
204 if (types[i].flags() & QMetaType::NeedsDestruction)
205 types[i].destruct(values[i]);
213 void **a,
const QMetaType *types,
int argc, Callable call)
218 for (
int ii = 0; ii < argc; ++ii)
219 jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
224 jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject);
226 jsThisObject = engine->globalObject;
228 jsThisObject = engine->globalObject;
234 return !jsResult
->isUndefined();
236 const QMetaType resultType = types[0];
237 if (scope.hasException()) {
239 resultType.destruct(result);
240 resultType.construct(result);
241 }
else if (resultType == QMetaType::fromType<QVariant>()) {
244 *
static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {});
245 }
else if (!ExecutionEngine::metaTypeFromJS(jsResult, resultType, result)) {
248 resultType.destruct(result);
249 resultType.construct(result);
251 return !jsResult
->isUndefined();
280 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType)
282 QMetaType type = qmlType.qListTypeId();
283 const auto metaSequence = [&]() {
287 return qmlType.isSequentialContainer()
288 ? qmlType.listMetaSequence()
289 : QQmlMetaType::qmlListType(type).listMetaSequence();
292 if (
const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
293 if (sequence->d()->listType() == type)
294 return value.asReturnedValue();
297 if (
const QmlListWrapper *list = value.as<QmlListWrapper>()) {
298 if (list->d()->propertyType() == type)
299 return value.asReturnedValue();
302 QMetaType listValueType = qmlType.typeId();
303 if (!listValueType.isValid()) {
305 return value.asReturnedValue();
310 const ArrayObject *array = value.as<ArrayObject>();
312 return (listValueType.flags() & QMetaType::PointerToQObject)
313 ? QmlListWrapper::create(engine, listValueType)
314 : SequencePrototype::fromData(engine, type, metaSequence(),
nullptr);
317 if (listValueType.flags() & QMetaType::PointerToQObject) {
318 QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, type));
319 QQmlListProperty<QObject> *listProperty = newList->d()->property();
321 const qsizetype length = array->getLength();
324 for (; i < length; ++i) {
326 listProperty->append(listProperty, coerceQObject(v, qmlType));
329 return newList->asReturnedValue();
332 QV4::Scoped<Sequence> sequence(
333 scope, SequencePrototype::fromData(engine, type, metaSequence(),
nullptr));
334 const qsizetype length = array->getLength();
336 for (qsizetype i = 0; i < length; ++i) {
340 return sequence->asReturnedValue();
344 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType,
bool isList)
350 return coerceListType(engine, value, qmlType);
352 const QMetaType metaType = qmlType.typeId();
353 if (!metaType.isValid()) {
354 if (!value.isUndefined())
356 return value.asReturnedValue();
359 switch (metaType.id()) {
360 case QMetaType::Void:
361 return Encode::undefined();
362 case QMetaType::QVariant:
363 return value.asReturnedValue();
365 return Encode(value.toInt32());
366 case QMetaType::Double:
367 return value.convertedToNumber();
368 case QMetaType::QString:
369 return value.toString(engine)->asReturnedValue();
370 case QMetaType::Bool:
371 return Encode(value.toBoolean());
372 case QMetaType::QDateTime:
374 return value.asReturnedValue();
375 if (
const VariantObject *varObject = value.as<VariantObject>()) {
376 const QVariant &var = varObject->d()->data();
377 switch (var.metaType().id()) {
378 case QMetaType::QDateTime:
379 return engine->newDateObject(var.value<QDateTime>())->asReturnedValue();
380 case QMetaType::QTime:
381 return engine->newDateObject(var.value<QTime>(),
nullptr, -1, 0)->asReturnedValue();
382 case QMetaType::QDate:
383 return engine->newDateObject(var.value<QDate>(),
nullptr, -1, 0)->asReturnedValue();
388 return engine->newDateObject(QDateTime())->asReturnedValue();
389 case QMetaType::QUrl:
390 if (value.as<UrlObject>())
391 return value.asReturnedValue();
392 if (
const VariantObject *varObject = value.as<VariantObject>()) {
393 const QVariant &var = varObject->d()->data();
394 return var.metaType() == QMetaType::fromType<QUrl>()
395 ? engine->newUrlObject(var.value<QUrl>())->asReturnedValue()
396 : engine->newUrlObject()->asReturnedValue();
399 if (
const String *string = value.stringValue())
400 return engine->newUrlObject(QUrl(string->toQString()))->asReturnedValue();
401 return engine->newUrlObject()->asReturnedValue();
402#if QT_CONFIG(regularexpression)
403 case QMetaType::QRegularExpression:
404 if (value.as<RegExpObject>())
405 return value.asReturnedValue();
406 if (
const VariantObject *varObject = value.as<VariantObject>()) {
407 const QVariant &var = varObject->d()->data();
408 if (var.metaType() == QMetaType::fromType<QRegularExpression>())
409 return engine->newRegExpObject(var.value<QRegularExpression>())->asReturnedValue();
411 return engine->newRegExpObject(QString(), 0)->asReturnedValue();
417 if (metaType.flags() & QMetaType::PointerToQObject) {
418 return coerceQObject(value, qmlType)
419 ? value.asReturnedValue()
423 if (
const QQmlValueTypeWrapper *wrapper = value.as<QQmlValueTypeWrapper>()) {
424 if (wrapper->type() == metaType)
425 return value.asReturnedValue();
428 if (
void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value, engine)) {
429 Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
430 nullptr, metaType, qmlType.metaObjectForValueType(),
431 nullptr, -1, Heap::ReferenceObject::NoFlag);
432 Q_ASSERT(!wrapper->gadgetPtr());
433 wrapper->setGadgetPtr(target);
434 return wrapper->asReturnedValue();
437 return Encode::undefined();
442 ExecutionEngine *engine,
443 const Function::JSTypedFunction *typedFunction,
const CompiledData::Function *compiledFunction,
444 const Value *argv,
int argc, Callable call)
449 const CompiledData::Parameter *formals = compiledFunction->formalsTable();
450 for (qsizetype i = 0; i < jsCallData
.argc; ++i) {
451 jsCallData.args[i] = coerce(
452 engine, i < argc ? argv[i] : QV4::Value::fromReturnedValue(Encode::undefined()),
453 typedFunction->types[i + 1], formals[i].type.isList());
457 return coerce(engine, result, typedFunction->types[0], compiledFunction->returnType.isList());
462 ExecutionEngine *engine, QMetaType fromType,
const void *from, QMetaType toType,
void *to)
464 if ((fromType.flags() & QMetaType::PointerToQObject)
465 && (toType.flags() & QMetaType::PointerToQObject)) {
466 QObject *fromObj = *
static_cast<QObject *
const*>(from);
467 *
static_cast<QObject **>(to)
468 = (fromObj && fromObj->metaObject()->inherits(toType.metaObject()))
474 if (toType == QMetaType::fromType<QVariant>()) {
475 new (to) QVariant(fromType, from);
479 if (toType == QMetaType::fromType<QJSPrimitiveValue>()) {
480 new (to) QJSPrimitiveValue(fromType, from);
484 if (fromType == QMetaType::fromType<QVariant>()) {
485 const QVariant *fromVariant =
static_cast<
const QVariant *>(from);
486 if (fromVariant->metaType() == toType)
487 toType.construct(to, fromVariant->data());
489 coerce(engine, fromVariant->metaType(), fromVariant->data(), toType, to);
493 if (fromType == QMetaType::fromType<QJSPrimitiveValue>()) {
494 const QJSPrimitiveValue *fromPrimitive =
static_cast<
const QJSPrimitiveValue *>(from);
495 if (fromPrimitive->metaType() == toType)
496 toType.construct(to, fromPrimitive->data());
498 coerce(engine, fromPrimitive->metaType(), fromPrimitive->data(), toType, to);
505 if (toType.flags() & QMetaType::NeedsConstruction)
506 toType.construct(to);
509 if (!ExecutionEngine::metaTypeFromJS(value, toType, to))
510 QMetaType::convert(fromType, from, toType, to);
515 ExecutionEngine *engine,
const TypedFunction *typedFunction,
516 void **argv,
const QMetaType *types,
int argc, Callable call)
519 const qsizetype numFunctionArguments = typedFunction->parameterCount();
521 Q_ALLOCA_DECLARE(
void *, transformedArguments);
522 Q_ALLOCA_DECLARE(
void, transformedResult);
524 const QMetaType returnType = typedFunction->returnMetaType();
525 const QMetaType frameReturn = types[0];
526 bool returnsQVariantWrapper =
false;
527 if (argv[0] && returnType != frameReturn) {
528 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
529 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
531 if (frameReturn == QMetaType::fromType<QVariant>()) {
532 QVariant *returnValue =
static_cast<QVariant *>(argv[0]);
533 *returnValue = QVariant(returnType);
534 transformedResult = transformedArguments[0] = returnValue->data();
535 returnsQVariantWrapper =
true;
536 }
else if (returnType.sizeOf() > 0) {
537 Q_ALLOCA_ASSIGN(
void, transformedResult, returnType.sizeOf());
538 transformedArguments[0] = transformedResult;
539 if (returnType.flags() & QMetaType::NeedsConstruction)
540 returnType.construct(transformedResult);
542 transformedResult = transformedArguments[0] = &argc;
546 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
547 const bool isValid = argc > i;
548 const QMetaType frameType = isValid ? types[i + 1] : QMetaType();
550 const QMetaType argumentType = typedFunction->parameterMetaType(i);
551 if (isValid && argumentType == frameType)
554 if (transformedArguments ==
nullptr) {
555 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
556 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
559 if (argumentType.sizeOf() == 0) {
560 transformedArguments[i + 1] =
nullptr;
564 void *frameVal = isValid ? argv[i + 1] :
nullptr;
565 if (isValid && frameType == QMetaType::fromType<QVariant>()) {
566 QVariant *variant =
static_cast<QVariant *>(frameVal);
568 const QMetaType variantType = variant->metaType();
569 if (variantType == argumentType) {
572 transformedArguments[i + 1] = argv[i + 1] = variant->data();
574 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
575 coerce(engine, variantType, variant->constData(), argumentType, arg);
576 transformedArguments[i + 1] = arg;
581 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
584 coerce(engine, frameType, frameVal, argumentType, arg);
586 argumentType.construct(arg);
588 transformedArguments[i + 1] = arg;
591 if (!transformedArguments) {
592 call(argv, numFunctionArguments);
596 call(transformedArguments, numFunctionArguments);
598 if (transformedResult && !returnsQVariantWrapper) {
599 if (frameReturn.sizeOf() > 0) {
600 if (frameReturn.flags() & QMetaType::NeedsDestruction)
601 frameReturn.destruct(argv[0]);
602 coerce(engine, returnType, transformedResult, frameReturn, argv[0]);
604 if (returnType.flags() & QMetaType::NeedsDestruction)
605 returnType.destruct(transformedResult);
608 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
609 void *arg = transformedArguments[i + 1];
612 if (i >= argc || arg != argv[i + 1]) {
613 const QMetaType argumentType = typedFunction->parameterMetaType(i);
614 if (argumentType.flags() & QMetaType::NeedsDestruction)
615 argumentType.destruct(arg);