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)
160 Q_ALLOCA_VAR(
void *, values, numTypes *
sizeof(
void *));
162 for (qsizetype i = 1; i < numTypes; ++i) {
163 const QMetaType argumentType = types[i];
164 if (
const qsizetype argumentSize = argumentType.sizeOf()) {
165 Q_ALLOCA_VAR(
void, argument, argumentSize);
166 const int argIndex = i - 1;
167 if (argumentType.flags() & QMetaType::NeedsConstruction)
168 argumentType.construct(argument);
171 || !ExecutionEngine::metaTypeFromJS(argv[argIndex], argumentType, argument)) {
172 if (!errorHandler(argumentType, argument, argIndex)) {
173 for (qsizetype j = 1; j < i; ++j) {
174 if (types[j].flags() & QMetaType::NeedsDestruction)
175 types[j].destruct(values[j]);
177 return Encode::undefined();
181 values[i] = argument;
187 Q_ALLOCA_DECLARE(
void, returnValue);
188 if (
const qsizetype returnSize = types[0].sizeOf()) {
189 Q_ALLOCA_ASSIGN(
void, returnValue, returnSize);
190 constructReturnValue(types[0], returnValue);
191 values[0] = returnValue;
196 call(values, types, argc);
198 const ReturnedValue result = values[0]
199 ? convertReturnValue(engine, types[0], returnValue)
200 : Encode::undefined();
202 for (qsizetype i = 1, end = numTypes; i <
end; ++i) {
203 if (types[i].flags() & QMetaType::NeedsDestruction)
204 types[i].destruct(values[i]);
212 void **a,
const QMetaType *types,
int argc, Callable call)
217 for (
int ii = 0; ii < argc; ++ii)
218 jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
223 jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject);
225 jsThisObject = engine->globalObject;
227 jsThisObject = engine->globalObject;
233 return !jsResult
->isUndefined();
235 const QMetaType resultType = types[0];
236 if (scope.hasException()) {
238 resultType.destruct(result);
239 resultType.construct(result);
240 }
else if (resultType == QMetaType::fromType<QVariant>()) {
243 *
static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {});
244 }
else if (!ExecutionEngine::metaTypeFromJS(jsResult, resultType, result)) {
247 resultType.destruct(result);
248 resultType.construct(result);
250 return !jsResult
->isUndefined();
279 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType)
281 QMetaType type = qmlType.qListTypeId();
282 const auto metaSequence = [&]() {
286 return qmlType.isSequentialContainer()
287 ? qmlType.listMetaSequence()
288 : QQmlMetaType::qmlListType(type).listMetaSequence();
291 if (
const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
292 if (sequence->d()->listType() == type)
293 return value.asReturnedValue();
296 if (
const QmlListWrapper *list = value.as<QmlListWrapper>()) {
297 if (list->d()->propertyType() == type)
298 return value.asReturnedValue();
301 QMetaType listValueType = qmlType.typeId();
302 if (!listValueType.isValid()) {
304 return value.asReturnedValue();
309 const ArrayObject *array = value.as<ArrayObject>();
311 return (listValueType.flags() & QMetaType::PointerToQObject)
312 ? QmlListWrapper::create(engine, listValueType)
313 : SequencePrototype::fromData(engine, type, metaSequence(),
nullptr);
316 if (listValueType.flags() & QMetaType::PointerToQObject) {
317 QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, type));
318 QQmlListProperty<QObject> *listProperty = newList->d()->property();
320 const qsizetype length = array->getLength();
323 for (; i < length; ++i) {
325 listProperty->append(listProperty, coerceQObject(v, qmlType));
328 return newList->asReturnedValue();
331 QV4::Scoped<Sequence> sequence(
332 scope, SequencePrototype::fromData(engine, type, metaSequence(),
nullptr));
333 const qsizetype length = array->getLength();
335 for (qsizetype i = 0; i < length; ++i) {
339 return sequence->asReturnedValue();
343 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType,
bool isList)
349 return coerceListType(engine, value, qmlType);
351 const QMetaType metaType = qmlType.typeId();
352 if (!metaType.isValid()) {
353 if (!value.isUndefined())
355 return value.asReturnedValue();
358 switch (metaType.id()) {
359 case QMetaType::Void:
360 return Encode::undefined();
361 case QMetaType::QVariant:
362 return value.asReturnedValue();
364 return Encode(value.toInt32());
365 case QMetaType::Double:
366 return value.convertedToNumber();
367 case QMetaType::QString:
368 return value.toString(engine)->asReturnedValue();
369 case QMetaType::Bool:
370 return Encode(value.toBoolean());
371 case QMetaType::QDateTime:
373 return value.asReturnedValue();
374 if (
const VariantObject *varObject = value.as<VariantObject>()) {
375 const QVariant &var = varObject->d()->data();
376 switch (var.metaType().id()) {
377 case QMetaType::QDateTime:
378 return engine->newDateObject(var.value<QDateTime>())->asReturnedValue();
379 case QMetaType::QTime:
380 return engine->newDateObject(var.value<QTime>(),
nullptr, -1, 0)->asReturnedValue();
381 case QMetaType::QDate:
382 return engine->newDateObject(var.value<QDate>(),
nullptr, -1, 0)->asReturnedValue();
387 return engine->newDateObject(QDateTime())->asReturnedValue();
388 case QMetaType::QUrl:
389 if (value.as<UrlObject>())
390 return value.asReturnedValue();
391 if (
const VariantObject *varObject = value.as<VariantObject>()) {
392 const QVariant &var = varObject->d()->data();
393 return var.metaType() == QMetaType::fromType<QUrl>()
394 ? engine->newUrlObject(var.value<QUrl>())->asReturnedValue()
395 : engine->newUrlObject()->asReturnedValue();
398 if (
const String *string = value.stringValue())
399 return engine->newUrlObject(QUrl(string->toQString()))->asReturnedValue();
400 return engine->newUrlObject()->asReturnedValue();
401#if QT_CONFIG(regularexpression)
402 case QMetaType::QRegularExpression:
403 if (value.as<RegExpObject>())
404 return value.asReturnedValue();
405 if (
const VariantObject *varObject = value.as<VariantObject>()) {
406 const QVariant &var = varObject->d()->data();
407 if (var.metaType() == QMetaType::fromType<QRegularExpression>())
408 return engine->newRegExpObject(var.value<QRegularExpression>())->asReturnedValue();
410 return engine->newRegExpObject(QString(), 0)->asReturnedValue();
416 if (metaType.flags() & QMetaType::PointerToQObject) {
417 return coerceQObject(value, qmlType)
418 ? value.asReturnedValue()
422 if (
const QQmlValueTypeWrapper *wrapper = value.as<QQmlValueTypeWrapper>()) {
423 if (wrapper->type() == metaType)
424 return value.asReturnedValue();
427 if (
void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value, engine)) {
428 Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
429 nullptr, metaType, qmlType.metaObjectForValueType(),
430 nullptr, -1, Heap::ReferenceObject::NoFlag);
431 Q_ASSERT(!wrapper->gadgetPtr());
432 wrapper->setGadgetPtr(target);
433 return wrapper->asReturnedValue();
436 return Encode::undefined();
441 ExecutionEngine *engine,
442 const Function::JSTypedFunction *typedFunction,
const CompiledData::Function *compiledFunction,
443 const Value *argv,
int argc, Callable call)
448 const CompiledData::Parameter *formals = compiledFunction->formalsTable();
449 for (qsizetype i = 0; i < jsCallData
.argc; ++i) {
450 jsCallData.args[i] = coerce(
451 engine, i < argc ? argv[i] : QV4::Value::fromReturnedValue(Encode::undefined()),
452 typedFunction->types[i + 1], formals[i].type.isList());
456 return coerce(engine, result, typedFunction->types[0], compiledFunction->returnType.isList());
461 ExecutionEngine *engine, QMetaType fromType,
const void *from, QMetaType toType,
void *to)
463 if ((fromType.flags() & QMetaType::PointerToQObject)
464 && (toType.flags() & QMetaType::PointerToQObject)) {
465 QObject *fromObj = *
static_cast<QObject *
const*>(from);
466 *
static_cast<QObject **>(to)
467 = (fromObj && fromObj->metaObject()->inherits(toType.metaObject()))
473 if (toType == QMetaType::fromType<QVariant>()) {
474 new (to) QVariant(fromType, from);
478 if (toType == QMetaType::fromType<QJSPrimitiveValue>()) {
479 new (to) QJSPrimitiveValue(fromType, from);
483 if (fromType == QMetaType::fromType<QVariant>()) {
484 const QVariant *fromVariant =
static_cast<
const QVariant *>(from);
485 if (fromVariant->metaType() == toType)
486 toType.construct(to, fromVariant->data());
488 coerce(engine, fromVariant->metaType(), fromVariant->data(), toType, to);
492 if (fromType == QMetaType::fromType<QJSPrimitiveValue>()) {
493 const QJSPrimitiveValue *fromPrimitive =
static_cast<
const QJSPrimitiveValue *>(from);
494 if (fromPrimitive->metaType() == toType)
495 toType.construct(to, fromPrimitive->data());
497 coerce(engine, fromPrimitive->metaType(), fromPrimitive->data(), toType, to);
504 if (toType.flags() & QMetaType::NeedsConstruction)
505 toType.construct(to);
508 if (!ExecutionEngine::metaTypeFromJS(value, toType, to))
509 QMetaType::convert(fromType, from, toType, to);
514 ExecutionEngine *engine,
const TypedFunction *typedFunction,
515 void **argv,
const QMetaType *types,
int argc, Callable call)
517 const qsizetype numFunctionArguments = typedFunction->parameterCount();
519 Q_ALLOCA_DECLARE(
void *, transformedArguments);
520 Q_ALLOCA_DECLARE(
void, transformedResult);
522 const QMetaType returnType = typedFunction->returnMetaType();
523 const QMetaType frameReturn = types[0];
524 bool returnsQVariantWrapper =
false;
525 if (argv[0] && returnType != frameReturn) {
526 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
527 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
529 if (frameReturn == QMetaType::fromType<QVariant>()) {
530 QVariant *returnValue =
static_cast<QVariant *>(argv[0]);
531 *returnValue = QVariant(returnType);
532 transformedResult = transformedArguments[0] = returnValue->data();
533 returnsQVariantWrapper =
true;
534 }
else if (returnType.sizeOf() > 0) {
535 Q_ALLOCA_ASSIGN(
void, transformedResult, returnType.sizeOf());
536 transformedArguments[0] = transformedResult;
537 if (returnType.flags() & QMetaType::NeedsConstruction)
538 returnType.construct(transformedResult);
540 transformedResult = transformedArguments[0] = &argc;
544 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
545 const bool isValid = argc > i;
546 const QMetaType frameType = isValid ? types[i + 1] : QMetaType();
548 const QMetaType argumentType = typedFunction->parameterMetaType(i);
549 if (isValid && argumentType == frameType)
552 if (transformedArguments ==
nullptr) {
553 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
554 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
557 if (argumentType.sizeOf() == 0) {
558 transformedArguments[i + 1] =
nullptr;
562 void *frameVal = isValid ? argv[i + 1] :
nullptr;
563 if (isValid && frameType == QMetaType::fromType<QVariant>()) {
564 QVariant *variant =
static_cast<QVariant *>(frameVal);
566 const QMetaType variantType = variant->metaType();
567 if (variantType == argumentType) {
570 transformedArguments[i + 1] = argv[i + 1] = variant->data();
572 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
573 coerce(engine, variantType, variant->constData(), argumentType, arg);
574 transformedArguments[i + 1] = arg;
579 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
582 coerce(engine, frameType, frameVal, argumentType, arg);
584 argumentType.construct(arg);
586 transformedArguments[i + 1] = arg;
589 if (!transformedArguments) {
590 call(argv, numFunctionArguments);
594 call(transformedArguments, numFunctionArguments);
596 if (transformedResult && !returnsQVariantWrapper) {
597 if (frameReturn.sizeOf() > 0) {
598 if (frameReturn.flags() & QMetaType::NeedsDestruction)
599 frameReturn.destruct(argv[0]);
600 coerce(engine, returnType, transformedResult, frameReturn, argv[0]);
602 if (returnType.flags() & QMetaType::NeedsDestruction)
603 returnType.destruct(transformedResult);
606 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
607 void *arg = transformedArguments[i + 1];
610 if (i >= argc || arg != argv[i + 1]) {
611 const QMetaType argumentType = typedFunction->parameterMetaType(i);
612 if (argumentType.flags() & QMetaType::NeedsDestruction)
613 argumentType.destruct(arg);