Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlvaluetypewrapper.cpp
Go to the documentation of this file.
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
5
6#include <private/qqmlvaluetype_p.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlglobal_p.h>
9#include <private/qqmlbuiltinfunctions_p.h>
10
11#include <private/qv4engine_p.h>
12#include <private/qv4functionobject_p.h>
13#include <private/qv4variantobject_p.h>
14#include <private/qv4alloca_p.h>
15#include <private/qv4stackframe_p.h>
16#include <private/qv4objectiterator_p.h>
17#include <private/qv4qobjectwrapper_p.h>
18#include <private/qv4identifiertable_p.h>
19#include <private/qv4lookup_p.h>
20#include <private/qv4sequenceobject_p.h>
21#include <private/qv4arraybuffer_p.h>
22#include <private/qv4dateobject_p.h>
23#include <private/qv4jsonobject_p.h>
24#if QT_CONFIG(regularexpression)
25#include <private/qv4regexpobject_p.h>
26#endif
27#if QT_CONFIG(qml_locale)
28#include <private/qqmllocale_p.h>
29#endif
30#include <QtCore/qloggingcategory.h>
31#include <QtCore/qdatetime.h>
32#include <QtCore/QLine>
33#include <QtCore/QLineF>
34#include <QtCore/QSize>
35#include <QtCore/QSizeF>
36#include <QtCore/QTimeZone>
37
39
40Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
41
42DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
43
44namespace QV4 {
45
46Heap::QQmlValueTypeWrapper *Heap::QQmlValueTypeWrapper::detached() const
47{
48 return internalClass->engine->memoryManager->allocate<QV4::QQmlValueTypeWrapper>(
49 m_gadgetPtr, QMetaType(m_metaType), m_metaObject, nullptr, -1, NoFlag);
50}
51
52void Heap::QQmlValueTypeWrapper::destroy()
53{
54 if (m_gadgetPtr) {
55 metaType().destruct(m_gadgetPtr);
56 ::operator delete(m_gadgetPtr);
57 }
58 ReferenceObject::destroy();
59}
60
61QVariant Heap::QQmlValueTypeWrapper::toVariant() const
62{
63 Q_ASSERT(gadgetPtr());
64 return QVariant(metaType(), gadgetPtr());
65}
66
67bool Heap::QQmlValueTypeWrapper::setVariant(const QVariant &variant)
68{
69 Q_ASSERT(isVariant());
70
71 const QMetaType variantReferenceType = variant.metaType();
72 if (variantReferenceType != metaType()) {
73 // This is a stale VariantReference. That is, the variant has been
74 // overwritten with a different type in the meantime.
75 // We need to modify this reference to the updated value type, if
76 // possible, or return false if it is not a value type.
77 if (QQmlMetaType::isValueType(variantReferenceType)) {
78 const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(variantReferenceType);
79 if (gadgetPtr()) {
80 metaType().destruct(gadgetPtr());
81 ::operator delete(gadgetPtr());
82 }
83 setGadgetPtr(nullptr);
84 setMetaObject(mo);
85 setMetaType(variantReferenceType);
86 if (!mo)
87 return false;
88 } else {
89 return false;
90 }
91 }
92
94 return true;
95}
96
97void *Heap::QQmlValueTypeWrapper::storagePointer()
98{
99 if (!gadgetPtr()) {
100 setGadgetPtr(::operator new(metaType().sizeOf()));
101 metaType().construct(gadgetPtr(), nullptr);
102 }
103 return gadgetPtr();
104}
105
106bool Heap::QQmlValueTypeWrapper::readReference()
107{
108 // If locations are enforced we only read once
109 return enforcesLocation() || QV4::ReferenceObject::readReference(this);
110}
111
112bool Heap::QQmlValueTypeWrapper::writeBack(int propertyIndex)
113{
114 return isAttachedToProperty() && QV4::ReferenceObject::writeBack(this, propertyIndex);
115}
116
117ReturnedValue QQmlValueTypeWrapper::create(
118 ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object)
119{
120 QV4::Scope scope(engine);
121 initProto(engine);
122
123 // Either we're enforcing the location, then we have to read right away.
124 // Or we don't then we lazy-load. In neither case we pass any data.
125 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
126 nullptr, cloneFrom->metaType(), cloneFrom->metaObject(),
127 object, cloneFrom->property(), cloneFrom->flags()));
128 r->d()->setLocation(cloneFrom->function(), cloneFrom->statementIndex());
129 if (cloneFrom->enforcesLocation())
131 return r->asReturnedValue();
132}
133
134void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
135{
136 if (v4->valueTypeWrapperPrototype()->d_unchecked())
137 return;
138
139 Scope scope(v4);
140 ScopedObject o(scope, v4->newObject());
141 o->defineDefaultProperty(v4->id_toString(), method_toString, 1);
143}
144
145int QQmlValueTypeWrapper::virtualMetacall(
146 Object *object, QMetaObject::Call call, int index, void **a)
147{
150
151 switch (call) {
156 if (wrapper->d()->object())
157 wrapper->d()->readReference();
158 break;
159 default:
160 break;
161 }
162
163 const QMetaObject *mo = wrapper->d()->metaObject();
164 if (!mo->d.static_metacall)
165 return 0;
166
167 mo->d.static_metacall(static_cast<QObject *>(wrapper->d()->gadgetPtr()), call, index, a);
168
169 switch (call) {
171 break;
174 if (wrapper->d()->object())
175 wrapper->d()->writeBack(index);
176 break;
179 if (wrapper->d()->object())
180 wrapper->d()->writeBack();
181 break;
182 default:
183 break;
184 }
185
186 return -1;
187}
188
189ReturnedValue QQmlValueTypeWrapper::create(
191 Heap::Object *object, int property, Heap::ReferenceObject::Flags flags)
192{
193 Scope scope(engine);
194 initProto(engine);
195
196 if (!type.isValid()) {
197 return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
198 .arg(QString::fromUtf8(type.name())));
199 }
200
201 // If data is given explicitly, we assume it has just been read from the property
202 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
203 data, type, metaObject, object, property, flags));
204 if (CppStackFrame *frame = engine->currentStackFrame)
205 r->d()->setLocation(frame->v4Function, frame->statementNumber());
206 if (!data && r->d()->enforcesLocation())
208 return r->asReturnedValue();
209}
210
211ReturnedValue QQmlValueTypeWrapper::create(
213{
214 Scope scope(engine);
215 initProto(engine);
216
217 if (!type.isValid()) {
218 return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
219 .arg(QString::fromUtf8(type.name())));
220 }
221
223 scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
224 data, type, metaObject, nullptr, -1, Heap::ReferenceObject::NoFlag));
225 return r->asReturnedValue();
226}
227
228QVariant QQmlValueTypeWrapper::toVariant() const
229{
230 if (d()->isReference() && !readReferenceValue())
231 return QVariant();
232 return d()->toVariant();
233}
234
235bool QQmlValueTypeWrapper::toGadget(void *data) const
236{
237 if (d()->isReference() && !readReferenceValue())
238 return false;
239 const QMetaType type = d()->metaType();
240 type.destruct(data);
241 type.construct(data, d()->gadgetPtr());
242 return true;
243}
244
245bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
246{
247 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other);
249
250 if (QV4::VariantObject *rv = other->as<VariantObject>())
251 return lv->isEqual(rv->d()->data());
252
254 return lv->isEqual(v->toVariant());
255
256 return false;
257}
258
259bool QQmlValueTypeWrapper::virtualHasProperty(const Managed *m, PropertyKey id)
260{
261 if (!id.isString())
262 return Object::virtualHasProperty(m, id);
263 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>());
264 auto wrapper = static_cast<const QQmlValueTypeWrapper *>(m);
265 if (auto mo = wrapper->d()->metaObject())
266 if (mo->indexOfProperty(id.toQString().toUtf8()) != -1)
267 return true;
268
269 /* we don't want to fallback to QObject::virtualHasProperty
270 as that would end up calling getOwnProperty which is wasteful,
271 as it calls our own virtualGetOwnProperty.
272 As we know that our own properties are only those found on the meta-object,
273 we can instead skip the call, and simply check whether the property exists
274 on the prototype.
275 */
276 Scope scope(m->engine());
277 ScopedObject o(scope, m);
278 o = o->getPrototypeOf();
279 if (o)
280 return o->hasProperty(id);
281
282 return false;
283}
284
285static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
286{
287 return metaObject->property(index).isWritable()
288 ? (Heap::ReferenceObject::CanWriteBack | Heap::ReferenceObject::EnforcesLocation)
289 : Heap::ReferenceObject::EnforcesLocation;
290}
291
293 const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper,
294 int index, void **args)
295{
296 metaObject->d.static_metacall(
297 reinterpret_cast<QObject*>(
298 valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty, index, args);
299}
300
302 Heap::QQmlValueTypeWrapper *valueTypeWrapper,
303 QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
304{
305 if (isFunction) {
306 // calling a Q_INVOKABLE function of a value type
307 return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
308 }
309
310 const QMetaObject *metaObject = valueTypeWrapper->metaObject();
311 int index = coreIndex;
312
313 const auto wrapChar16 = [engine](char16_t c) {
314 return engine->newString(QChar(c));
315 };
316 const auto wrapQObject = [engine](QObject *object) {
317 return QObjectWrapper::wrap(engine, object);
318 };
319 const auto wrapJsonValue = [engine](const QJsonValue &value) {
320 return JsonObject::fromJsonValue(engine, value);
321 };
322 const auto wrapJsonObject = [engine](const QJsonObject &object) {
323 return JsonObject::fromJsonObject(engine, object);
324 };
325 const auto wrapJsonArray = [engine](const QJsonArray &array) {
326 return JsonObject::fromJsonArray(engine, array);
327 };
328
329 const auto wrapQDateTime = [&](const QDateTime &dateTime) {
330 return engine->newDateObject(
331 dateTime, valueTypeWrapper, index, referenceFlags(metaObject, index));
332 };
333 const auto wrapQDate = [&](QDate date) {
334 return engine->newDateObject(
335 date, valueTypeWrapper, index, referenceFlags(metaObject, index));
336 };
337 const auto wrapQTime = [&](QTime time) {
338 return engine->newDateObject(
339 time, valueTypeWrapper, index, referenceFlags(metaObject, index));
340 };
341
342#if QT_CONFIG(qml_locale)
343 const auto wrapLocale = [engine](const QLocale &locale) {
344 return QQmlLocale::wrap(engine, locale);
345 };
346#endif
347
348#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
349 case metatype: { \
350 cpptype v; \
351 void *args[] = { &v, nullptr }; \
352 doStaticReadCall(metaObject, valueTypeWrapper, index, args); \
353 return QV4::Encode(constructor(v)); \
354 }
355
358
359 const int metaTypeId = isEnum
360 ? metaType.underlyingType().id()
361 : (metaType.flags() & QMetaType::PointerToQObject)
362 ? QMetaType::QObjectStar
363 : metaType.id();
364
365 switch (metaTypeId) {
367 case QMetaType::Void:
368 return Encode::undefined();
369 case QMetaType::Nullptr:
370 case QMetaType::VoidStar:
371 return Encode::null();
372 VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
373 VALUE_TYPE_LOAD(QMetaType::Int, int, int);
374 VALUE_TYPE_LOAD(QMetaType::UInt, uint, uint);
375 VALUE_TYPE_LOAD(QMetaType::Long, long, double);
376 VALUE_TYPE_LOAD(QMetaType::ULong, ulong, double);
377 VALUE_TYPE_LOAD(QMetaType::LongLong, qlonglong, double);
378 VALUE_TYPE_LOAD(QMetaType::ULongLong, qulonglong, double);
379 VALUE_TYPE_LOAD(QMetaType::Double, double, double);
380 VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
381 VALUE_TYPE_LOAD(QMetaType::QByteArray, QByteArray, engine->newArrayBuffer);
382 VALUE_TYPE_LOAD(QMetaType::Float, float, float);
383 VALUE_TYPE_LOAD(QMetaType::Short, short, int);
384 VALUE_TYPE_LOAD(QMetaType::UShort, unsigned short, int);
385 VALUE_TYPE_LOAD(QMetaType::Char, char, int);
386 VALUE_TYPE_LOAD(QMetaType::UChar, unsigned char, int);
387 VALUE_TYPE_LOAD(QMetaType::SChar, signed char, int);
388 VALUE_TYPE_LOAD(QMetaType::QChar, QChar, engine->newString);
389 VALUE_TYPE_LOAD(QMetaType::Char16, char16_t, wrapChar16);
390 VALUE_TYPE_LOAD(QMetaType::QDateTime, QDateTime, wrapQDateTime);
391 VALUE_TYPE_LOAD(QMetaType::QDate, QDate, wrapQDate);
392 VALUE_TYPE_LOAD(QMetaType::QTime, QTime, wrapQTime);
393#if QT_CONFIG(regularexpression)
394 VALUE_TYPE_LOAD(QMetaType::QRegularExpression, QRegularExpression, engine->newRegExpObject);
395#endif
396 VALUE_TYPE_LOAD(QMetaType::QObjectStar, QObject*, wrapQObject);
397 VALUE_TYPE_LOAD(QMetaType::QJsonValue, QJsonValue, wrapJsonValue);
398 VALUE_TYPE_LOAD(QMetaType::QJsonObject, QJsonObject, wrapJsonObject);
399 VALUE_TYPE_LOAD(QMetaType::QJsonArray, QJsonArray, wrapJsonArray);
400#if QT_CONFIG(qml_locale)
401 VALUE_TYPE_LOAD(QMetaType::QLocale, QLocale, wrapLocale);
402#endif
403 case QMetaType::QPixmap:
404 case QMetaType::QImage: {
405 QVariant v(metaType);
406 void *args[] = { v.data(), nullptr };
407 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
408 return Encode(engine->newVariantObject(metaType, v.data()));
409 }
410 case QMetaType::QVariant: {
411 QVariant v;
412 void *args[] = { &v, nullptr };
413 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
414 return engine->fromVariant(
415 v, valueTypeWrapper, index,
416 referenceFlags(metaObject, index) | Heap::ReferenceObject::IsVariant);
417 }
418 default:
419 break;
420 }
421
422 QVariant v(metaType);
423 void *args[] = { v.data(), nullptr };
424 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
425 return engine->fromVariant(v, valueTypeWrapper, index, referenceFlags(metaObject, index));
426#undef VALUE_TYPE_LOAD
427}
428
429PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
430{
431 if (id.isString()) {
432 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
433 Q_ASSERT(r);
434
435 const QQmlPropertyData result = r->dataForPropertyKey(id);
436 if (!result.isValid())
437 return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
438
439 if (!p)
440 return Attr_Data; // Property exists, but we're not interested in the value
441
442 if (!r->d()->isReference() || r->readReferenceValue()) {
443 // Property exists, and we can retrieve it
444 p->value = getGadgetProperty(
445 r->engine(), r->d(), result.propType(), result.coreIndex(),
446 result.isFunction(), result.isEnum());
447 } else {
448 // Property exists, but we can't retrieve it. Make it undefined.
449 p->value = Encode::undefined();
450 }
451
452 return Attr_Data;
453 }
454
456}
457
459{
460 int propertyIndex = 0;
462 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
463
464};
465
466PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
467 const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
468
469 if (that->d()->isReference() && !that->readReferenceValue())
470 return PropertyKey::invalid();
471
472 const QMetaObject *mo = that->d()->metaObject();
473 // We don't return methods, ie. they are not visible when iterating
474 const int propertyCount = mo->propertyCount();
475 if (propertyIndex < propertyCount) {
476 Scope scope(that->engine());
477 QMetaProperty p = mo->property(propertyIndex); // TODO: Implement and use QBasicMetaProperty
478 ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(p.name())));
479 ++propertyIndex;
480 if (attrs)
482 if (pd) {
484 data.load(p);
485 pd->value = getGadgetProperty(that->engine(), that->d(), data.propType(), data.coreIndex(), data.isFunction(), data.isEnum());
486 }
487 return propName->toPropertyKey();
488 }
489
490 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
491}
492
493
494OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
495{
496 *target = *m;
498}
499
500bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
501{
502 if (d()->isReference() && !readReferenceValue())
503 return false;
504 int id1 = value.metaType().id();
505 QVariant v = d()->toVariant();
506 int id2 = v.metaType().id();
507 if (id1 != id2) {
508 // conversions for weak comparison
509 switch (id1) {
510 case QMetaType::QPoint:
511 if (id2 == QMetaType::QPointF)
512 return value.value<QPointF>() == v.value<QPointF>();
513 break;
514 case QMetaType::QPointF:
515 if (id2 == QMetaType::QPoint)
516 return value.value<QPointF>() == v.value<QPointF>();
517 break;
518 case QMetaType::QRect:
519 if (id2 == QMetaType::QRectF)
520 return value.value<QRectF>() == v.value<QRectF>();
521 break;
522 case QMetaType::QRectF:
523 if (id2 == QMetaType::QRect)
524 return value.value<QRectF>() == v.value<QRectF>();
525 break;
526 case QMetaType::QLine:
527 if (id2 == QMetaType::QLineF)
528 return value.value<QLineF>() == v.value<QLineF>();
529 break;
530 case QMetaType::QLineF:
531 if (id2 == QMetaType::QLine)
532 return value.value<QLineF>() == v.value<QLineF>();
533 break;
534 case QMetaType::QSize:
535 if (id2 == QMetaType::QSizeF)
536 return value.value<QSizeF>() == v.value<QSizeF>();
537 break;
538 case QMetaType::QSizeF:
539 if (id2 == QMetaType::QSize)
540 return value.value<QSizeF>() == v.value<QSizeF>();
541 break;
542 default:
543 break;
544 }
545 }
546 return (value == v);
547}
548
549int QQmlValueTypeWrapper::typeId() const
550{
551 return d()->metaType().id();
552}
553
554QMetaType QQmlValueTypeWrapper::type() const
555{
556 return d()->metaType();
557}
558
559bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
560{
561 bool destructGadgetOnExit = false;
562 Q_ALLOCA_DECLARE(void, gadget);
563 if (d()->isReference()) {
564 if (!d()->gadgetPtr()) {
565 Q_ALLOCA_ASSIGN(void, gadget, d()->metaType().sizeOf());
566 d()->setGadgetPtr(gadget);
567 d()->metaType().construct(d()->gadgetPtr(), nullptr);
568 destructGadgetOnExit = true;
569 }
570 if (!readReferenceValue())
571 return false;
572 }
573
574 int flags = 0;
575 int status = -1;
576 void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
578
579 if (destructGadgetOnExit) {
580 d()->metaType().destruct(d()->gadgetPtr());
581 d()->setGadgetPtr(nullptr);
582 }
583 return true;
584}
585
586QQmlPropertyData QQmlValueTypeWrapper::dataForPropertyKey(PropertyKey id) const
587{
588 if (!id.isStringOrSymbol())
589 return QQmlPropertyData {};
590 QByteArray name = id.asStringOrSymbol()->toQString().toUtf8();
591 const QMetaObject *mo = d()->metaObject();
594 if (metaMethod.isValid()) {
595 result.load(metaMethod);
596 } else {
597 int propertyIndex = d()->metaObject()->indexOfProperty(name.constData());
598 if (propertyIndex >= 0)
599 result.load(mo->property(propertyIndex));
600 }
601 return result;
602}
603
604ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
605{
606 const Object *o = thisObject->as<Object>();
607 if (!o)
608 return b->engine()->throwTypeError();
610 if (!w)
611 return b->engine()->throwTypeError();
612
613 if (w->d()->isReference() && !w->readReferenceValue())
615
617 if (!QMetaType::convert(w->d()->metaType(), w->d()->gadgetPtr(),
618 QMetaType(QMetaType::QString), &result)) {
619 result = QString::fromUtf8(w->d()->metaType().name()) + QLatin1Char('(');
620 const QMetaObject *mo = w->d()->metaObject();
621 const int propCount = mo->propertyCount();
622 for (int i = 0; i < propCount; ++i) {
623 if (mo->property(i).isDesignable()) {
624 QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr());
625 if (i > 0)
626 result += QLatin1String(", ");
627 result += value.toString();
628 }
629 }
630 result += QLatin1Char(')');
631 }
632 return Encode(b->engine()->newString(result));
633}
634
635ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
636 Lookup *lookup)
637{
638 PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
639 runtimeStrings[lookup->nameIndex]);
640 if (!id.isString())
641 return Object::virtualResolveLookupGetter(object, engine, lookup);
642
643 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(object);
644 QV4::ExecutionEngine *v4 = r->engine();
645 Scope scope(v4);
646 ScopedString name(scope, id.asStringOrSymbol());
647
648 // Note: readReferenceValue() can change the reference->type.
649 if (r->d()->isReference() && !r->readReferenceValue())
650 return Value::undefinedValue().asReturnedValue();
651
652 QQmlPropertyData result = r->dataForPropertyKey(id);
653 if (!result.isValid())
654 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
655
656 lookup->qgadgetLookup.ic = r->internalClass();
657 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
658 lookup->qgadgetLookup.metaObject = quintptr(r->d()->metaObject()) + 1;
659 lookup->qgadgetLookup.metaType = result.propType().iface();
660 lookup->qgadgetLookup.coreIndex = result.coreIndex();
661 lookup->qgadgetLookup.isFunction = result.isFunction();
662 lookup->qgadgetLookup.isEnum = result.isEnum();
663 lookup->getter = QQmlValueTypeWrapper::lookupGetter;
664 return lookup->getter(lookup, engine, *object);
665}
666
667ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
668{
669 const auto revertLookup = [lookup, engine, &object]() {
670 lookup->qgadgetLookup.metaObject = quintptr(0);
671 lookup->getter = Lookup::getterGeneric;
672 return Lookup::getterGeneric(lookup, engine, object);
673 };
674
675 // we can safely cast to a QV4::Object here. If object is something else,
676 // the internal class won't match
677 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
678 if (!o || o->internalClass != lookup->qgadgetLookup.ic)
679 return revertLookup();
680
681 Heap::QQmlValueTypeWrapper *valueTypeWrapper =
682 const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
683 if (valueTypeWrapper->metaObject() != reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1))
684 return revertLookup();
685
686 if (valueTypeWrapper->isReference() && !valueTypeWrapper->readReference())
687 return Encode::undefined();
688
689 return getGadgetProperty(
690 engine, valueTypeWrapper, QMetaType(lookup->qgadgetLookup.metaType),
692 lookup->qgadgetLookup.isEnum);
693}
694
695bool QQmlValueTypeWrapper::lookupSetter(
696 Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
697{
698 return QV4::Lookup::setterFallback(l, engine, object, value);
699}
700
701bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
702 const Value &value)
703{
704 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
705}
706
707ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
708{
710
711 if (!id.isString())
712 return Object::virtualGet(m, id, receiver, hasProperty);
713
714 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
715 QV4::ExecutionEngine *v4 = r->engine();
716
717 // Note: readReferenceValue() can change the reference->type.
718 if (r->d()->isReference() && !r->readReferenceValue())
719 return Value::undefinedValue().asReturnedValue();
720
721 QQmlPropertyData result = r->dataForPropertyKey(id);
722 if (!result.isValid())
723 return Object::virtualGet(m, id, receiver, hasProperty);
724
725 if (hasProperty)
726 *hasProperty = true;
727
728 return getGadgetProperty(v4, r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
729}
730
731bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
732{
733 if (!id.isString())
734 return Object::virtualPut(m, id, value, receiver);
735
737 ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
738 Scope scope(v4);
739 if (scope.hasException())
740 return false;
741
743 Heap::Object *heapObject = nullptr;
744 if (r->d()->isReference()) {
745 heapObject = r->d()->object();
746 if (!r->readReferenceValue() || !r->d()->canWriteBack())
747 return false;
748 }
749
750 const QMetaObject *metaObject = r->d()->metaObject();
751 const QQmlPropertyData pd = r->dataForPropertyKey(id);
752 if (!pd.isValid())
753 return false;
754
755 if (heapObject) {
756 QObject *referenceObject = nullptr;
758 const int referencePropertyIndex = r->d()->property();
759 QV4::Scoped<QV4::QObjectWrapper> o(scope, heapObject);
760 if (o) {
761 referenceObject = o->object();
762 } else {
763 QV4::Scoped<QV4::QQmlTypeWrapper> t(scope, heapObject);
764 if (t)
765 referenceObject = t->object();
766 }
767
768 if (f) {
769 if (!f->isBinding()) {
770 // assigning a JS function to a non-var-property is not allowed.
771 QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
772 ScopedString e(scope, v4->newString(error));
773 v4->throwError(e);
774 return false;
775 }
776
777 if (!referenceObject) {
778 QString error = QStringLiteral("Cannot create binding on nested value type property");
779 ScopedString e(scope, v4->newString(error));
780 v4->throwError(e);
781 return false;
782 }
783
784 const QMetaProperty writebackProperty
785 = referenceObject->metaObject()->property(referencePropertyIndex);
786 const QMetaType writeBackPropertyType = writebackProperty.metaType();
787
789
790 QQmlPropertyData cacheData;
791 cacheData.setWritable(true);
792 cacheData.setPropType(writeBackPropertyType);
793 cacheData.setCoreIndex(referencePropertyIndex);
794
795 QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
796
797 QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
798 QV4::ScopedContext ctx(scope, f->scope());
799 QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
800 newBinding->setSourceLocation(bindingFunction->currentLocation());
801 if (f->isBoundFunction())
802 newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
803 newBinding->setSourceLocation(bindingFunction->currentLocation());
804 newBinding->setTarget(referenceObject, cacheData, &pd);
806 return true;
807 } else if (referenceObject) {
808 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
809 if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
810 Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
811 const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
812 const auto stackFrame = v4->currentStackFrame;
813 qCInfo(lcBindingRemoval,
814 "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
815 referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
816 qPrintable(qmlBinding->expressionIdentifier()),
817 metaObject->property(pd.coreIndex()).name(),
818 qPrintable(stackFrame->source()), stackFrame->lineNumber());
819 }
820 }
821 QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()));
822 }
823 }
824
825 QMetaProperty property = metaObject->property(pd.coreIndex());
826 Q_ASSERT(property.isValid());
827 if (value.isUndefined() && pd.isResettable()) {
828 property.resetOnGadget(reinterpret_cast<QObject *>(r->d()->gadgetPtr()));
829 if (heapObject)
830 r->d()->writeBack(pd.coreIndex());
831 return true;
832 }
833
835
836 if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
837 v = v.toInt();
838
839 void *gadget = r->d()->gadgetPtr();
840 property.writeOnGadget(gadget, std::move(v));
841
842 if (heapObject)
843 r->d()->writeBack(pd.coreIndex());
844
845 return true;
846}
847
848} // namespace QV4
849
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
\inmodule QtCore\reentrant
Definition qdatetime.h:257
\inmodule QtCore \reentrant
Definition qdatetime.h:27
T fromVariant(const QVariant &value)
Returns the given value converted to the template type {T}.
Definition qjsengine.h:115
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
\inmodule QtCore\reentrant
Definition qjsonvalue.h:24
\inmodule QtCore
Definition qline.h:182
pointer data()
Definition qlist.h:414
\inmodule QtCore
Definition qmetaobject.h:18
bool isValid() const
\inmodule QtCore
QMetaType metaType() const
\inmodule QtCore
Definition qmetatype.h:320
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
QMetaType underlyingType() const
int id(int=0) const
Definition qmetatype.h:454
@ PointerToQObject
Definition qmetatype.h:385
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:324
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to)
Converts the object at from from fromType to the preallocated space at to typed toType.
friend class QVariant
Definition qmetatype.h:775
\inmodule QtCore
Definition qobject.h:90
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4187
\inmodule QtCore\reentrant
Definition qpoint.h:214
void setTarget(const QQmlProperty &)
void setBoundFunction(QV4::BoundFunction *boundFunction)
void setSourceLocation(const QQmlSourceLocation &location)
static QQmlBinding * create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *)
static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static bool isValueType(QMetaType type)
bool isResettable() const
void setCoreIndex(int idx)
void setPropType(QMetaType pt)
void setWritable(bool onoff)
static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags=None, QQmlPropertyData::WriteFlags writeFlags=QQmlPropertyData::DontRemoveBinding)
static void removeBinding(const QQmlProperty &that)
static QQmlAbstractBinding * binding(QObject *, QQmlPropertyIndex index)
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsize.h:207
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
\inmodule QtCore \reentrant
Definition qdatetime.h:189
\inmodule QtCore
Definition qvariant.h:64
QMetaType metaType() const
const void * constData() const
Definition qvariant.h:446
EGLContext ctx
QDate date
[1]
double e
auto mo
[7]
short next
Definition keywords.cpp:445
Q_QML_PRIVATE_EXPORT QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale)
Combined button and popup list for selecting options.
\qmltype Particle \inqmlmodule QtQuick.Particles
static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
quint64 ReturnedValue
static void doStaticReadCall(const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper, int index, void **args)
@ Attr_Invalid
@ Attr_Data
static ReturnedValue getGadgetProperty(ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueTypeWrapper, QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
static void * context
#define Q_UNLIKELY(x)
DBusConnection const char DBusError * error
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCInfo(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLuint object
[3]
GLfloat GLfloat f
GLenum type
GLenum target
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLsizei propCount
GLuint name
const GLubyte * c
GLenum array
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
unsigned short quint16
Definition qtypes.h:43
size_t quintptr
Definition qtypes.h:72
unsigned long ulong
Definition qtypes.h:30
quint64 qulonglong
Definition qtypes.h:59
unsigned int uint
Definition qtypes.h:29
qint64 qlonglong
Definition qtypes.h:58
#define Q_ALLOCA_ASSIGN(type, name, size)
Definition qv4alloca_p.h:66
#define Q_ALLOCA_DECLARE(type, name)
Definition qv4alloca_p.h:62
#define RETURN_UNDEFINED()
#define DEFINE_OBJECT_VTABLE(classname)
const char property[13]
Definition qwizard.cpp:101
mimeData setData("text/csv", csvData)
obj metaObject() -> className()
QVariant variant
[1]
QDateTime dateTime
[12]
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
QJSValueList args
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17
static Q_CORE_EXPORT QMetaMethod firstMethod(const QMetaObject *baseObject, QByteArrayView name)
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
CppStackFrame * currentStackFrame
QQmlRefPointer< QQmlContextData > callingQmlContext() const
Heap::String * newString(const QString &s=QString())
ReturnedValue throwError(const Value &value)
String * id_toString() const
Heap::Object * newObject()
Object * valueTypeWrapperPrototype() const
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
ReturnedValue throwTypeError()
Pointer< InternalClass *, 0 > internalClass
Definition qv4heap_p.h:63
struct QV4::Lookup::@576::@604 qgadgetLookup
ReturnedValue(* getter)(Lookup *l, ExecutionEngine *engine, const Value &object)
Definition qv4lookup_p.h:36
const QtPrivate::QMetaTypeInterface * metaType
quintptr metaObject
static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
Heap::InternalClass * ic
Definition qv4lookup_p.h:51
ExecutionEngine * engine() const
static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index)
~QQmlValueTypeWrapperOwnPropertyKeyIterator() override=default
const QMetaObject * metaObject() const
bool isEqual(const QVariant &value) const
static bool writeBack(HeapObject *ref, int internalIndex=AllProperties)
static bool readReference(HeapObject *ref)
bool hasException() const
static constexpr VTable::GetOwnProperty virtualGetOwnProperty
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter
const T * as() const
Definition qv4value_p.h:132
void wrapper()