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 auto failConversion = [&]() {
165 for (qsizetype j = 1; j < i; ++j) {
166 if (types[j].flags() & QMetaType::NeedsDestruction)
167 types[j].destruct(values[j]);
169 return Encode::undefined();
172 const QMetaType argumentType = types[i];
173 if (
const qsizetype argumentSize = argumentType.sizeOf()) {
174 Q_ALLOCA_VAR(
void, argument, argumentSize);
175 const int argIndex = i - 1;
176 if (argumentType.flags() & QMetaType::NeedsConstruction)
177 argumentType.construct(argument);
179 if (argIndex < argc) {
180 if (argumentType == QMetaType::fromType<QVariant>()) {
183 *
static_cast<QVariant *>(argument) =
184 ExecutionEngine::toVariant(argv[argIndex], QMetaType{ });
185 }
else if (!ExecutionEngine::metaTypeFromJS(argv[argIndex], argumentType, argument)
186 && !errorHandler(argumentType, argument, argIndex)) {
187 return failConversion();
190 return failConversion();
193 values[i] = argument;
199 Q_ALLOCA_DECLARE(
void, returnValue);
200 if (
const qsizetype returnSize = types[0].sizeOf()) {
201 Q_ALLOCA_ASSIGN(
void, returnValue, returnSize);
202 constructReturnValue(types[0], returnValue);
203 values[0] = returnValue;
208 call(values, types, argc);
210 const ReturnedValue result = values[0]
211 ? convertReturnValue(engine, types[0], returnValue)
212 : Encode::undefined();
214 for (qsizetype i = 1, end = numTypes; i <
end; ++i) {
215 if (types[i].flags() & QMetaType::NeedsDestruction)
216 types[i].destruct(values[i]);
224 void **a,
const QMetaType *types,
int argc, Callable call)
229 for (
int ii = 0; ii < argc; ++ii)
230 jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
235 jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject);
237 jsThisObject = engine->globalObject;
239 jsThisObject = engine->globalObject;
245 return !jsResult
->isUndefined();
247 const QMetaType resultType = types[0];
248 if (scope.hasException()) {
250 resultType.destruct(result);
251 resultType.construct(result);
252 }
else if (resultType == QMetaType::fromType<QVariant>()) {
255 *
static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {});
256 }
else if (!ExecutionEngine::metaTypeFromJS(jsResult, resultType, result)) {
259 resultType.destruct(result);
260 resultType.construct(result);
262 return !jsResult
->isUndefined();
291 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType)
293 QMetaType type = qmlType.qListTypeId();
294 const auto metaSequence = [&]() {
298 return qmlType.isSequentialContainer()
299 ? qmlType.listMetaSequence()
300 : QQmlMetaType::qmlListType(type).listMetaSequence();
303 if (
const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
304 if (sequence->d()->listType() == type)
305 return value.asReturnedValue();
308 if (
const QmlListWrapper *list = value.as<QmlListWrapper>()) {
309 if (list->d()->propertyType() == type)
310 return value.asReturnedValue();
313 QMetaType listValueType = qmlType.typeId();
314 if (!listValueType.isValid()) {
316 return value.asReturnedValue();
321 const ArrayObject *array = value.as<ArrayObject>();
323 return (listValueType.flags() & QMetaType::PointerToQObject)
324 ? QmlListWrapper::create(engine, listValueType)
325 : SequencePrototype::fromData(engine, type, metaSequence(),
nullptr);
328 if (listValueType.flags() & QMetaType::PointerToQObject) {
329 QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, type));
330 QQmlListProperty<QObject> *listProperty = newList->d()->property();
332 const qsizetype length = array->getLength();
335 for (; i < length; ++i) {
337 listProperty->append(listProperty, coerceQObject(v, qmlType));
340 return newList->asReturnedValue();
343 QV4::Scoped<Sequence> sequence(
344 scope, SequencePrototype::fromData(engine, type, metaSequence(),
nullptr));
345 const qsizetype length = array->getLength();
347 for (qsizetype i = 0; i < length; ++i) {
351 return sequence->asReturnedValue();
355 ExecutionEngine *engine,
const Value &value,
const QQmlType &qmlType,
bool isList)
361 return coerceListType(engine, value, qmlType);
363 const QMetaType metaType = qmlType.typeId();
364 if (!metaType.isValid()) {
365 if (!value.isUndefined())
367 return value.asReturnedValue();
370 switch (metaType.id()) {
371 case QMetaType::Void:
372 return Encode::undefined();
373 case QMetaType::QVariant:
374 return value.asReturnedValue();
376 return Encode(value.toInt32());
377 case QMetaType::Double:
378 return value.convertedToNumber();
379 case QMetaType::QString:
380 return value.toString(engine)->asReturnedValue();
381 case QMetaType::Bool:
382 return Encode(value.toBoolean());
383 case QMetaType::QDateTime:
385 return value.asReturnedValue();
386 if (
const VariantObject *varObject = value.as<VariantObject>()) {
387 const QVariant &var = varObject->d()->data();
388 switch (var.metaType().id()) {
389 case QMetaType::QDateTime:
390 return engine->newDateObject(var.value<QDateTime>())->asReturnedValue();
391 case QMetaType::QTime:
392 return engine->newDateObject(var.value<QTime>(),
nullptr, -1, 0)->asReturnedValue();
393 case QMetaType::QDate:
394 return engine->newDateObject(var.value<QDate>(),
nullptr, -1, 0)->asReturnedValue();
399 return engine->newDateObject(QDateTime())->asReturnedValue();
400 case QMetaType::QUrl:
401 if (value.as<UrlObject>())
402 return value.asReturnedValue();
403 if (
const VariantObject *varObject = value.as<VariantObject>()) {
404 const QVariant &var = varObject->d()->data();
405 return var.metaType() == QMetaType::fromType<QUrl>()
406 ? engine->newUrlObject(var.value<QUrl>())->asReturnedValue()
407 : engine->newUrlObject()->asReturnedValue();
410 if (
const String *string = value.stringValue())
411 return engine->newUrlObject(QUrl(string->toQString()))->asReturnedValue();
412 return engine->newUrlObject()->asReturnedValue();
413#if QT_CONFIG(regularexpression)
414 case QMetaType::QRegularExpression:
415 if (value.as<RegExpObject>())
416 return value.asReturnedValue();
417 if (
const VariantObject *varObject = value.as<VariantObject>()) {
418 const QVariant &var = varObject->d()->data();
419 if (var.metaType() == QMetaType::fromType<QRegularExpression>())
420 return engine->newRegExpObject(var.value<QRegularExpression>())->asReturnedValue();
422 return engine->newRegExpObject(QString(), 0)->asReturnedValue();
428 if (metaType.flags() & QMetaType::PointerToQObject) {
429 return coerceQObject(value, qmlType)
430 ? value.asReturnedValue()
434 if (
const QQmlValueTypeWrapper *wrapper = value.as<QQmlValueTypeWrapper>()) {
435 if (wrapper->type() == metaType)
436 return value.asReturnedValue();
439 if (
void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value, engine)) {
440 Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
441 nullptr, metaType, qmlType.metaObjectForValueType(),
442 nullptr, -1, Heap::ReferenceObject::NoFlag);
443 Q_ASSERT(!wrapper->gadgetPtr());
444 wrapper->setGadgetPtr(target);
445 return wrapper->asReturnedValue();
448 return Encode::undefined();
453 ExecutionEngine *engine,
454 const Function::JSTypedFunction *typedFunction,
const CompiledData::Function *compiledFunction,
455 const Value *argv,
int argc, Callable call)
460 const CompiledData::Parameter *formals = compiledFunction->formalsTable();
461 for (qsizetype i = 0; i < jsCallData
.argc; ++i) {
462 jsCallData
.args[i] = coerce(
463 engine, i < argc ? argv[i] : QV4::Value::fromReturnedValue(Encode::undefined()),
464 typedFunction->types[i + 1], formals[i].type.isList());
468 return coerce(engine, result, typedFunction->types[0], compiledFunction->returnType.isList());
473 ExecutionEngine *engine, QMetaType fromType,
const void *from, QMetaType toType,
void *to)
475 if ((fromType.flags() & QMetaType::PointerToQObject)
476 && (toType.flags() & QMetaType::PointerToQObject)) {
477 QObject *fromObj = *
static_cast<QObject *
const*>(from);
478 *
static_cast<QObject **>(to)
479 = (fromObj && fromObj->metaObject()->inherits(toType.metaObject()))
485 if (toType == QMetaType::fromType<QVariant>()) {
486 new (to) QVariant(fromType, from);
490 if (toType == QMetaType::fromType<QJSPrimitiveValue>()) {
491 new (to) QJSPrimitiveValue(fromType, from);
495 if (fromType == QMetaType::fromType<QVariant>()) {
496 const QVariant *fromVariant =
static_cast<
const QVariant *>(from);
497 if (fromVariant->metaType() == toType)
498 toType.construct(to, fromVariant->data());
500 coerce(engine, fromVariant->metaType(), fromVariant->data(), toType, to);
504 if (fromType == QMetaType::fromType<QJSPrimitiveValue>()) {
505 const QJSPrimitiveValue *fromPrimitive =
static_cast<
const QJSPrimitiveValue *>(from);
506 if (fromPrimitive->metaType() == toType)
507 toType.construct(to, fromPrimitive->data());
509 coerce(engine, fromPrimitive->metaType(), fromPrimitive->data(), toType, to);
516 if (toType.flags() & QMetaType::NeedsConstruction)
517 toType.construct(to);
520 if (!ExecutionEngine::metaTypeFromJS(value, toType, to))
521 QMetaType::convert(fromType, from, toType, to);
526 ExecutionEngine *engine,
const TypedFunction *typedFunction,
527 void **argv,
const QMetaType *types,
int argc, Callable call)
530 const qsizetype numFunctionArguments = typedFunction->parameterCount();
532 Q_ALLOCA_DECLARE(
void *, transformedArguments);
533 Q_ALLOCA_DECLARE(
void, transformedResult);
535 const QMetaType returnType = typedFunction->returnMetaType();
536 const QMetaType frameReturn = types[0];
537 bool returnsQVariantWrapper =
false;
538 if (argv[0] && returnType != frameReturn) {
539 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
540 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
542 if (frameReturn == QMetaType::fromType<QVariant>()) {
543 QVariant *returnValue =
static_cast<QVariant *>(argv[0]);
544 *returnValue = QVariant(returnType);
545 transformedResult = transformedArguments[0] = returnValue->data();
546 returnsQVariantWrapper =
true;
547 }
else if (returnType.sizeOf() > 0) {
548 Q_ALLOCA_ASSIGN(
void, transformedResult, returnType.sizeOf());
549 transformedArguments[0] = transformedResult;
550 if (returnType.flags() & QMetaType::NeedsConstruction)
551 returnType.construct(transformedResult);
553 transformedResult = transformedArguments[0] = &argc;
557 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
558 const bool isValid = argc > i;
559 const QMetaType frameType = isValid ? types[i + 1] : QMetaType();
561 const QMetaType argumentType = typedFunction->parameterMetaType(i);
562 if (isValid && argumentType == frameType)
565 if (transformedArguments ==
nullptr) {
566 Q_ALLOCA_ASSIGN(
void *, transformedArguments, (numFunctionArguments + 1) *
sizeof(
void *));
567 memcpy(transformedArguments, argv, (argc + 1) *
sizeof(
void *));
570 if (argumentType.sizeOf() == 0) {
571 transformedArguments[i + 1] =
nullptr;
575 void *frameVal = isValid ? argv[i + 1] :
nullptr;
576 if (isValid && frameType == QMetaType::fromType<QVariant>()) {
577 QVariant *variant =
static_cast<QVariant *>(frameVal);
579 const QMetaType variantType = variant->metaType();
580 if (variantType == argumentType) {
583 transformedArguments[i + 1] = argv[i + 1] = variant->data();
585 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
586 coerce(engine, variantType, variant->constData(), argumentType, arg);
587 transformedArguments[i + 1] = arg;
592 Q_ALLOCA_VAR(
void, arg, argumentType.sizeOf());
595 coerce(engine, frameType, frameVal, argumentType, arg);
597 argumentType.construct(arg);
599 transformedArguments[i + 1] = arg;
602 if (!transformedArguments) {
603 call(argv, numFunctionArguments);
607 call(transformedArguments, numFunctionArguments);
609 if (transformedResult && !returnsQVariantWrapper) {
610 if (frameReturn.sizeOf() > 0) {
611 if (frameReturn.flags() & QMetaType::NeedsDestruction)
612 frameReturn.destruct(argv[0]);
613 coerce(engine, returnType, transformedResult, frameReturn, argv[0]);
615 if (returnType.flags() & QMetaType::NeedsDestruction)
616 returnType.destruct(transformedResult);
619 for (qsizetype i = 0; i < numFunctionArguments; ++i) {
620 void *arg = transformedArguments[i + 1];
623 if (i >= argc || arg != argv[i + 1]) {
624 const QMetaType argumentType = typedFunction->parameterMetaType(i);
625 if (argumentType.flags() & QMetaType::NeedsDestruction)
626 argumentType.destruct(arg);