1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 BasysKom GmbH.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtQml module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qqmlvmemetaobject_p.h"
42
43
44#include "qqml.h"
45#include <private/qqmlrefcount_p.h>
46#include "qqmlexpression.h"
47#include "qqmlexpression_p.h"
48#include "qqmlcontext_p.h"
49#include "qqmlbinding_p.h"
50#include "qqmlpropertyvalueinterceptor_p.h"
51
52#include <private/qqmlglobal_p.h>
53
54#include <private/qv4object_p.h>
55#include <private/qv4variantobject_p.h>
56#include <private/qv4functionobject_p.h>
57#include <private/qv4scopedvalue_p.h>
58#include <private/qv4jscall_p.h>
59#include <private/qv4qobjectwrapper_p.h>
60#include <private/qqmlpropertycachecreator_p.h>
61#include <private/qqmlpropertycachemethodarguments_p.h>
62
63QT_BEGIN_NAMESPACE
64
65static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
66{
67 QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
68 list->append(o);
69 static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
70}
71
72static int list_count(QQmlListProperty<QObject> *prop)
73{
74 QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
75 return list->count();
76}
77
78static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
79{
80 QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
81 return list->at(index);
82}
83
84static void list_clear(QQmlListProperty<QObject> *prop)
85{
86 QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
87 list->clear();
88 static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
89}
90
91QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
92 : QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1)
93{
94}
95
96QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
97{
98}
99
100void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
101{
102 if (!m_target || QQmlData::wasDeleted(m_target->object))
103 return;
104
105 if (m_index >= 0) {
106 QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine();
107 if (v4) {
108 QV4::Scope scope(v4);
109 QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
110 if (sp) {
111 QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + m_index };
112 index.set(v4, QV4::Value::nullValue());
113 }
114 }
115
116 m_target->activate(m_target->object, m_target->methodOffset() + m_index, nullptr);
117 }
118}
119
120void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index)
121{
122 m_target = target;
123 m_index = index;
124 setObject(obj);
125}
126
127class QQmlVMEMetaObjectEndpoint : public QQmlNotifierEndpoint
128{
129public:
130 QQmlVMEMetaObjectEndpoint();
131 void tryConnect();
132
133 QFlagPointer<QQmlVMEMetaObject> metaObject;
134};
135
136QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
137 : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint)
138{
139}
140
141void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **)
142{
143 QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e);
144 vmee->tryConnect();
145}
146
147void QQmlVMEMetaObjectEndpoint::tryConnect()
148{
149 Q_ASSERT(metaObject->compiledObject);
150 int aliasId = this - metaObject->aliasEndpoints;
151
152 if (metaObject.flag()) {
153 // This is actually notify
154 int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties;
155 metaObject->activate(metaObject->object, sigIdx, nullptr);
156 } else {
157 const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
158 if (!aliasData->isObjectAlias()) {
159 QQmlContextData *ctxt = metaObject->ctxt;
160 QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
161 if (!target)
162 return;
163
164 QQmlData *targetDData = QQmlData::get(target, /*create*/false);
165 if (!targetDData)
166 return;
167 int coreIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex).coreIndex();
168 const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
169 if (!pd)
170 return;
171
172 if (pd->notifyIndex() != -1)
173 connect(target, pd->notifyIndex(), ctxt->engine);
174 }
175
176 metaObject.setFlag();
177 }
178}
179
180
181QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache)
182 : object(obj),
183 cache(cache),
184 interceptors(nullptr),
185 hasAssignedMetaObjectData(false)
186{
187 QObjectPrivate *op = QObjectPrivate::get(obj);
188
189 if (op->metaObject) {
190 parent = op->metaObject;
191 // Use the extra flag in QBiPointer to know if we can safely cast parent.asT1() to QQmlVMEMetaObject*
192 parent.setFlagValue(QQmlData::get(obj)->hasVMEMetaObject);
193 } else {
194 parent = obj->metaObject();
195 }
196
197 op->metaObject = this;
198 QQmlData::get(obj)->hasInterceptorMetaObject = true;
199}
200
201QQmlInterceptorMetaObject::~QQmlInterceptorMetaObject()
202{
203
204}
205
206void QQmlInterceptorMetaObject::registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor)
207{
208 interceptor->m_propertyIndex = index;
209 interceptor->m_next = interceptors;
210 interceptors = interceptor;
211}
212
213int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
214{
215 Q_ASSERT(o == object);
216 Q_UNUSED(o);
217
218 if (intercept(c, id, a))
219 return -1;
220 return object->qt_metacall(c, id, a);
221}
222
223bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
224{
225 if (c == QMetaObject::WriteProperty && interceptors &&
226 !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) {
227
228 for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
229 if (vi->m_propertyIndex.coreIndex() != id)
230 continue;
231
232 const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
233 int type = QQmlData::get(object)->propertyCache->property(id)->propType();
234
235 if (type != QVariant::Invalid) {
236 if (valueIndex != -1) {
237 QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
238 Q_ASSERT(valueType);
239
240 //
241 // Consider the following case:
242 // color c = { 0.1, 0.2, 0.3 }
243 // interceptor exists on c.r
244 // write { 0.2, 0.4, 0.6 }
245 //
246 // The interceptor may choose not to update the r component at this
247 // point (for example, a behavior that creates an animation). But we
248 // need to ensure that the g and b components are updated correctly.
249 //
250 // So we need to perform a full write where the value type is:
251 // r = old value, g = new value, b = new value
252 //
253 // And then call the interceptor which may or may not write the
254 // new value to the r component.
255 //
256 // This will ensure that the other components don't contain stale data
257 // and any relevant signals are emitted.
258 //
259 // To achieve this:
260 // (1) Store the new value type as a whole (needed due to
261 // aliasing between a[0] and static storage in value type).
262 // (2) Read the entire existing value type from object -> valueType temp.
263 // (3) Read the previous value of the component being changed
264 // from the valueType temp.
265 // (4) Write the entire new value type into the temp.
266 // (5) Overwrite the component being changed with the old value.
267 // (6) Perform a full write to the value type (which may emit signals etc).
268 // (7) Issue the interceptor call with the new component value.
269 //
270
271 QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
272 QVariant newValue(type, a[0]);
273
274 valueType->read(object, id);
275 QVariant prevComponentValue = valueProp.read(valueType);
276
277 valueType->setValue(newValue);
278 QVariant newComponentValue = valueProp.read(valueType);
279
280 // Don't apply the interceptor if the intercepted value has not changed
281 bool updated = false;
282 if (newComponentValue != prevComponentValue) {
283 valueProp.write(valueType, prevComponentValue);
284 valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
285
286 vi->write(newComponentValue);
287 updated = true;
288 }
289
290 if (updated)
291 return true;
292 } else {
293 vi->write(QVariant(type, a[0]));
294 return true;
295 }
296 }
297 }
298 }
299 return false;
300}
301
302
303QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObject *o)
304{
305 if (!hasAssignedMetaObjectData) {
306 *static_cast<QMetaObject *>(this) = *cache->createMetaObject();
307
308 if (parent.isT1())
309 this->d.superdata = parent.asT1()->toDynamicMetaObject(o);
310 else
311 this->d.superdata = parent.asT2();
312
313 hasAssignedMetaObjectData = true;
314 }
315
316 return this;
317}
318
319QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
320 QObject *obj,
321 const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
322 : QQmlInterceptorMetaObject(obj, cache),
323 engine(engine),
324 ctxt(QQmlData::get(obj, true)->outerContext),
325 aliasEndpoints(nullptr), compilationUnit(qmlCompilationUnit), compiledObject(nullptr)
326{
327 Q_ASSERT(engine);
328 QQmlData::get(obj)->hasVMEMetaObject = true;
329
330 if (compilationUnit && qmlObjectId >= 0) {
331 compiledObject = compilationUnit->objectAt(qmlObjectId);
332
333 if (compiledObject->nProperties || compiledObject->nFunctions) {
334 uint size = compiledObject->nProperties + compiledObject->nFunctions;
335 if (size) {
336 QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size);
337 propertyAndMethodStorage.set(engine, data);
338 std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined());
339 }
340
341 // Need JS wrapper to ensure properties/methods are marked.
342 ensureQObjectWrapper();
343 }
344 }
345}
346
347QQmlVMEMetaObject::~QQmlVMEMetaObject()
348{
349 if (parent.isT1()) parent.asT1()->objectDestroyed(object);
350 delete [] aliasEndpoints;
351
352 qDeleteAll(varObjectGuards);
353}
354
355QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData() const
356{
357 if (propertyAndMethodStorage.isUndefined()) {
358 if (propertyAndMethodStorage.valueRef())
359 // in some situations, the QObject wrapper (and associated data,
360 // such as the varProperties array) will have been cleaned up, but the
361 // QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
362 // In this situation, return 0.
363 return nullptr;
364 }
365
366 return static_cast<QV4::MemberData*>(propertyAndMethodStorage.asManaged());
367}
368
369void QQmlVMEMetaObject::writeProperty(int id, int v)
370{
371 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
372 if (md)
373 md->set(engine, id, QV4::Value::fromInt32(v));
374}
375
376void QQmlVMEMetaObject::writeProperty(int id, bool v)
377{
378 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
379 if (md)
380 md->set(engine, id, QV4::Value::fromBoolean(v));
381}
382
383void QQmlVMEMetaObject::writeProperty(int id, double v)
384{
385 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
386 if (md)
387 md->set(engine, id, QV4::Value::fromDouble(v));
388}
389
390void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
391{
392 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
393 if (md)
394 md->set(engine, id, engine->newString(v));
395}
396
397void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
398{
399 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
400 if (md)
401 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
402}
403
404void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
405{
406 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
407 if (md)
408 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
409}
410
411void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
412{
413 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
414 if (md)
415 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
416}
417
418void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
419{
420 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
421 if (md)
422 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
423}
424
425void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
426{
427 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
428 if (md)
429 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
430}
431
432void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
433{
434 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
435 if (md)
436 md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
437}
438
439void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
440{
441 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
442 if (md)
443 md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v)));
444
445 QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
446 if (v && !guard) {
447 guard = new QQmlVMEVariantQObjectPtr();
448 varObjectGuards.append(guard);
449 }
450 if (guard)
451 guard->setGuardedValue(v, this, id);
452}
453
454int QQmlVMEMetaObject::readPropertyAsInt(int id) const
455{
456 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
457 if (!md)
458 return 0;
459
460 QV4::Scope scope(engine);
461 QV4::ScopedValue sv(scope, *(md->data() + id));
462 if (!sv->isInt32())
463 return 0;
464 return sv->integerValue();
465}
466
467bool QQmlVMEMetaObject::readPropertyAsBool(int id) const
468{
469 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
470 if (!md)
471 return false;
472
473 QV4::Scope scope(engine);
474 QV4::ScopedValue sv(scope, *(md->data() + id));
475 if (!sv->isBoolean())
476 return false;
477 return sv->booleanValue();
478}
479
480double QQmlVMEMetaObject::readPropertyAsDouble(int id) const
481{
482 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
483 if (!md)
484 return 0.0;
485
486 QV4::Scope scope(engine);
487 QV4::ScopedValue sv(scope, *(md->data() + id));
488 if (!sv->isDouble())
489 return 0.0;
490 return sv->doubleValue();
491}
492
493QString QQmlVMEMetaObject::readPropertyAsString(int id) const
494{
495 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
496 if (!md)
497 return QString();
498
499 QV4::Scope scope(engine);
500 QV4::ScopedValue sv(scope, *(md->data() + id));
501 if (QV4::String *s = sv->stringValue())
502 return s->toQString();
503 return QString();
504}
505
506QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const
507{
508 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
509 if (!md)
510 return QUrl();
511
512 QV4::Scope scope(engine);
513 QV4::ScopedValue sv(scope, *(md->data() + id));
514 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
515 if (!v || v->d()->data().type() != QVariant::Url)
516 return QUrl();
517 return v->d()->data().value<QUrl>();
518}
519
520QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const
521{
522 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
523 if (!md)
524 return QDate();
525
526 QV4::Scope scope(engine);
527 QV4::ScopedValue sv(scope, *(md->data() + id));
528 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
529 if (!v || v->d()->data().type() != QVariant::Date)
530 return QDate();
531 return v->d()->data().value<QDate>();
532}
533
534QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
535{
536 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
537 if (!md)
538 return QDateTime();
539
540 QV4::Scope scope(engine);
541 QV4::ScopedValue sv(scope, *(md->data() + id));
542 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
543 if (!v || v->d()->data().type() != QVariant::DateTime)
544 return QDateTime();
545 return v->d()->data().value<QDateTime>();
546}
547
548QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const
549{
550 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
551 if (!md)
552 return QSizeF();
553
554 QV4::Scope scope(engine);
555 QV4::ScopedValue sv(scope, *(md->data() + id));
556 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
557 if (!v || v->d()->data().type() != QVariant::SizeF)
558 return QSizeF();
559 return v->d()->data().value<QSizeF>();
560}
561
562QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const
563{
564 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
565 if (!md)
566 return QPointF();
567
568 QV4::Scope scope(engine);
569 QV4::ScopedValue sv(scope, *(md->data() + id));
570 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
571 if (!v || v->d()->data().type() != QVariant::PointF)
572 return QPointF();
573 return v->d()->data().value<QPointF>();
574}
575
576QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const
577{
578 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
579 if (!md)
580 return nullptr;
581
582 QV4::Scope scope(engine);
583 QV4::ScopedValue sv(scope, *(md->data() + id));
584 const QV4::QObjectWrapper *wrapper = sv->as<QV4::QObjectWrapper>();
585 if (!wrapper)
586 return nullptr;
587 return wrapper->object();
588}
589
590QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
591{
592 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
593 if (!md)
594 return nullptr;
595
596 QV4::Scope scope(engine);
597 QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id));
598 if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
599 QVariant variant(QVariant::fromValue(QList<QObject*>()));
600 v = engine->newVariantObject(variant);
601 md->set(engine, id, v);
602 }
603 return static_cast<QList<QObject *> *>(v->d()->data().data());
604}
605
606QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
607{
608 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
609 if (!md)
610 return QRectF();
611
612 QV4::Scope scope(engine);
613 QV4::ScopedValue sv(scope, *(md->data() + id));
614 const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
615 if (!v || v->d()->data().type() != QVariant::RectF)
616 return QRectF();
617 return v->d()->data().value<QRectF>();
618}
619
620#if defined(Q_OS_WINRT) && defined(_M_ARM)
621#pragma optimize("", off)
622#endif
623int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a)
624{
625 Q_ASSERT(o == object);
626 Q_UNUSED(o);
627
628 int id = _id;
629
630 if (intercept(c, _id, a))
631 return -1;
632
633 const int propertyCount = compiledObject ? int(compiledObject->nProperties) : 0;
634 const int aliasCount = compiledObject ? int(compiledObject->nAliases) : 0;
635 const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0;
636 const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0;
637
638 if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
639 if (id >= propOffset()) {
640 id -= propOffset();
641
642 if (id < propertyCount) {
643 const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id];
644 const QV4::CompiledData::BuiltinType t = property.builtinType();
645
646 // the context can be null if accessing var properties from cpp after re-parenting an item.
647 QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine);
648
649 const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t);
650
651 if (c == QMetaObject::ReadProperty) {
652 switch (t) {
653 case QV4::CompiledData::BuiltinType::Int:
654 *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
655 break;
656 case QV4::CompiledData::BuiltinType::Bool:
657 *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
658 break;
659 case QV4::CompiledData::BuiltinType::Real:
660 *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
661 break;
662 case QV4::CompiledData::BuiltinType::String:
663 *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
664 break;
665 case QV4::CompiledData::BuiltinType::Url:
666 *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
667 break;
668 case QV4::CompiledData::BuiltinType::Date:
669 *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
670 break;
671 case QV4::CompiledData::BuiltinType::DateTime:
672 *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
673 break;
674 case QV4::CompiledData::BuiltinType::Rect:
675 *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
676 break;
677 case QV4::CompiledData::BuiltinType::Size:
678 *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
679 break;
680 case QV4::CompiledData::BuiltinType::Point:
681 *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
682 break;
683 case QV4::CompiledData::BuiltinType::Variant:
684 *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
685 break;
686 case QV4::CompiledData::BuiltinType::Font:
687 case QV4::CompiledData::BuiltinType::Time:
688 case QV4::CompiledData::BuiltinType::Color:
689 case QV4::CompiledData::BuiltinType::Vector2D:
690 case QV4::CompiledData::BuiltinType::Vector3D:
691 case QV4::CompiledData::BuiltinType::Vector4D:
692 case QV4::CompiledData::BuiltinType::Matrix4x4:
693 case QV4::CompiledData::BuiltinType::Quaternion:
694 Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
695 if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
696 QVariant propertyAsVariant;
697 if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
698 propertyAsVariant = v->d()->data();
699 QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
700 }
701 break;
702 case QV4::CompiledData::BuiltinType::Var:
703 if (ep) {
704 *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
705 } else {
706 // if the context was disposed, we just return an invalid variant from read.
707 *reinterpret_cast<QVariant *>(a[0]) = QVariant();
708 }
709 break;
710 case QV4::CompiledData::BuiltinType::InvalidBuiltin:
711 if (property.isList) {
712 QList<QObject *> *list = readPropertyAsList(id);
713 QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
714 *p = QQmlListProperty<QObject>(object, list,
715 list_append, list_count, list_at,
716 list_clear);
717 p->dummy1 = this;
718 p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
719 } else {
720 *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
721 }
722 }
723
724 } else if (c == QMetaObject::WriteProperty) {
725 bool needActivate = false;
726 switch (t) {
727 case QV4::CompiledData::BuiltinType::Int:
728 needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
729 writeProperty(id, *reinterpret_cast<int *>(a[0]));
730 break;
731 case QV4::CompiledData::BuiltinType::Bool:
732 needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
733 writeProperty(id, *reinterpret_cast<bool *>(a[0]));
734 break;
735 case QV4::CompiledData::BuiltinType::Real:
736 needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
737 writeProperty(id, *reinterpret_cast<double *>(a[0]));
738 break;
739 case QV4::CompiledData::BuiltinType::String:
740 needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
741 writeProperty(id, *reinterpret_cast<QString *>(a[0]));
742 break;
743 case QV4::CompiledData::BuiltinType::Url:
744 needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
745 writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
746 break;
747 case QV4::CompiledData::BuiltinType::Date:
748 needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
749 writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
750 break;
751 case QV4::CompiledData::BuiltinType::DateTime:
752 needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
753 writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
754 break;
755 case QV4::CompiledData::BuiltinType::Rect:
756 needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
757 writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
758 break;
759 case QV4::CompiledData::BuiltinType::Size:
760 needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
761 writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
762 break;
763 case QV4::CompiledData::BuiltinType::Point:
764 needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
765 writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
766 break;
767 case QV4::CompiledData::BuiltinType::Variant:
768 writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
769 break;
770 case QV4::CompiledData::BuiltinType::Font:
771 case QV4::CompiledData::BuiltinType::Time:
772 case QV4::CompiledData::BuiltinType::Color:
773 case QV4::CompiledData::BuiltinType::Vector2D:
774 case QV4::CompiledData::BuiltinType::Vector3D:
775 case QV4::CompiledData::BuiltinType::Vector4D:
776 case QV4::CompiledData::BuiltinType::Matrix4x4:
777 case QV4::CompiledData::BuiltinType::Quaternion:
778 Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
779 if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
780 const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
781 if (!v) {
782 md->set(engine, id, engine->newVariantObject(QVariant()));
783 v = (md->data() + id)->as<QV4::VariantObject>();
784 QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
785 }
786 needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data());
787 QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data());
788 }
789 break;
790 case QV4::CompiledData::BuiltinType::Var:
791 if (ep)
792 writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
793 break;
794 case QV4::CompiledData::BuiltinType::InvalidBuiltin:
795 if (property.isList) {
796 // Writing such a property is not supported. Content is added through the list property
797 // methods.
798 } else {
799 needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
800 writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
801 }
802
803 }
804
805 if (needActivate)
806 activate(object, methodOffset() + id, nullptr);
807 }
808
809 return -1;
810 }
811
812 id -= propertyCount;
813
814 if (id < aliasCount) {
815 const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
816
817 if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
818 *reinterpret_cast<void **>(a[0]) = nullptr;
819
820 if (!ctxt) return -1;
821
822 while (aliasData->aliasToLocalAlias)
823 aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
824
825 QQmlContext *context = ctxt->asQQmlContext();
826 QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
827
828 QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
829 if (!target)
830 return -1;
831
832 connectAlias(id);
833
834 if (aliasData->isObjectAlias()) {
835 *reinterpret_cast<QObject **>(a[0]) = target;
836 return -1;
837 }
838
839 QQmlData *targetDData = QQmlData::get(target, /*create*/false);
840 if (!targetDData)
841 return -1;
842
843 QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
844 int coreIndex = encodedIndex.coreIndex();
845 const int valueTypePropertyIndex = encodedIndex.valueTypeIndex();
846
847 // Remove binding (if any) on write
848 if(c == QMetaObject::WriteProperty) {
849 int flags = *reinterpret_cast<int*>(a[3]);
850 if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
851 QQmlData *targetData = QQmlData::get(target);
852 if (targetData && targetData->hasBindingBit(coreIndex))
853 QQmlPropertyPrivate::removeBinding(target, encodedIndex);
854 }
855 }
856
857 if (valueTypePropertyIndex != -1) {
858 if (!targetDData->propertyCache)
859 return -1;
860 const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
861 // Value type property
862 QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
863 Q_ASSERT(valueType);
864
865 valueType->read(target, coreIndex);
866 int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
867
868 if (c == QMetaObject::WriteProperty)
869 valueType->write(target, coreIndex, nullptr);
870
871 return rv;
872
873 } else {
874 return QMetaObject::metacall(target, c, coreIndex, a);
875 }
876
877 }
878 return -1;
879
880 }
881
882 } else if(c == QMetaObject::InvokeMetaMethod) {
883
884 if (id >= methodOffset()) {
885
886 id -= methodOffset();
887 int plainSignals = signalCount + propertyCount + aliasCount;
888 if (id < plainSignals) {
889 activate(object, _id, a);
890 return -1;
891 }
892
893 id -= plainSignals;
894
895 if (id < methodCount) {
896 QQmlEngine *engine = ctxt->engine;
897 if (!engine)
898 return -1; // We can't run the method
899
900 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
901 QV4::ExecutionEngine *v4 = engine->handle();
902 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
903 QV4::Scope scope(v4);
904
905
906 QV4::ScopedFunctionObject function(scope, method(id));
907 if (!function) {
908 // The function was not compiled. There are some exceptional cases which the
909 // expression rewriter does not rewrite properly (e.g., \r-terminated lines
910 // are not rewritten correctly but this bug is deemed out-of-scope to fix for
911 // performance reasons; see QTBUG-24064) and thus compilation will have failed.
912 QQmlError e;
913 e.setDescription(QLatin1String("Exception occurred during compilation of "
914 "function: ")
915 + QString::fromUtf8(QMetaObject::method(_id)
916 .methodSignature()));
917 ep->warning(e);
918 return -1; // The dynamic method with that id is not available.
919 }
920
921 auto methodData = cache->method(_id);
922 auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr;
923
924 const unsigned int parameterCount = (arguments && arguments->names) ? arguments->names->count() : 0;
925 Q_ASSERT(parameterCount == function->formalParameterCount());
926
927 QV4::JSCallData jsCallData(scope, parameterCount);
928 *jsCallData->thisObject = v4->global();
929
930 for (uint ii = 0; ii < parameterCount; ++ii) {
931 jsCallData->args[ii] = scope.engine->metaTypeToJS(arguments->arguments[ii + 1], a[ii + 1]);
932 }
933
934 const int returnType = methodData->propType();
935 QV4::ScopedValue result(scope, function->call(jsCallData));
936 if (scope.hasException()) {
937 QQmlError error = scope.engine->catchExceptionAsQmlError();
938 if (error.isValid())
939 ep->warning(error);
940 if (a[0]) {
941 QMetaType::destruct(returnType, a[0]);
942 QMetaType::construct(returnType, a[0], nullptr);
943 }
944 } else {
945 if (a[0]) {
946 // When the return type is QVariant, JS objects are to be returned as QJSValue wrapped in
947 // QVariant.
948 if (returnType == QMetaType::QVariant)
949 *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
950 else
951 scope.engine->metaTypeFromJS(result, returnType, a[0]);
952 }
953 }
954
955 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
956 return -1;
957 }
958 return -1;
959 }
960 }
961
962 if (parent.isT1())
963 return parent.asT1()->metaCall(object, c, _id, a);
964 else
965 return object->qt_metacall(c, _id, a);
966}
967#if defined(Q_OS_WINRT) && defined(_M_ARM)
968#pragma optimize("", on)
969#endif
970
971QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
972{
973 if (!ctxt || !ctxt->isValid() || !compiledObject) {
974 qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
975 return QV4::Encode::undefined();
976 }
977
978 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
979 if (!md)
980 return QV4::Encode::undefined();
981
982 return (md->data() + index + compiledObject->nProperties)->asReturnedValue();
983}
984
985QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const
986{
987 Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
988
989 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
990 if (md)
991 return (md->data() + id)->asReturnedValue();
992 return QV4::Value::undefinedValue().asReturnedValue();
993}
994
995QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const
996{
997 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
998 if (md) {
999 const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>();
1000 if (wrapper)
1001 return QVariant::fromValue(wrapper->object());
1002 const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
1003 if (v)
1004 return v->d()->data();
1005 return engine->toVariant(*(md->data() + id), -1);
1006 }
1007 return QVariant();
1008}
1009
1010void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
1011{
1012 Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
1013
1014 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
1015 if (!md)
1016 return;
1017
1018 // Importantly, if the current value is a scarce resource, we need to ensure that it
1019 // gets automatically released by the engine if no other references to it exist.
1020 const QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>();
1021 if (oldVariant)
1022 oldVariant->removeVmePropertyReference();
1023
1024 QObject *valueObject = nullptr;
1025 QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
1026
1027 // And, if the new value is a scarce resource, we need to ensure that it does not get
1028 // automatically released by the engine until no other references to it exist.
1029 if (QV4::VariantObject *v = const_cast<QV4::VariantObject*>(value.as<QV4::VariantObject>())) {
1030 v->addVmePropertyReference();
1031 } else if (QV4::QObjectWrapper *wrapper = const_cast<QV4::QObjectWrapper*>(value.as<QV4::QObjectWrapper>())) {
1032 // We need to track this QObject to signal its deletion
1033 valueObject = wrapper->object();
1034
1035 // Do we already have a QObject guard for this property?
1036 if (valueObject && !guard) {
1037 guard = new QQmlVMEVariantQObjectPtr();
1038 varObjectGuards.append(guard);
1039 }
1040 }
1041
1042 if (guard)
1043 guard->setGuardedValue(valueObject, this, id);
1044
1045 // Write the value and emit change signal as appropriate.
1046 md->set(engine, id, value);
1047 activate(object, methodOffset() + id, nullptr);
1048}
1049
1050void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
1051{
1052 if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) {
1053 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
1054 if (!md)
1055 return;
1056
1057 // Importantly, if the current value is a scarce resource, we need to ensure that it
1058 // gets automatically released by the engine if no other references to it exist.
1059 const QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>();
1060 if (oldv)
1061 oldv->removeVmePropertyReference();
1062
1063 // And, if the new value is a scarce resource, we need to ensure that it does not get
1064 // automatically released by the engine until no other references to it exist.
1065 QV4::Scope scope(engine);
1066 QV4::ScopedValue newv(scope, engine->fromVariant(value));
1067 QV4::Scoped<QV4::VariantObject> v(scope, newv);
1068 if (!!v)
1069 v->addVmePropertyReference();
1070
1071 // Write the value and emit change signal as appropriate.
1072 QVariant currentValue = readPropertyAsVariant(id);
1073 md->set(engine, id, newv);
1074 if ((currentValue.userType() != value.userType() || currentValue != value))
1075 activate(object, methodOffset() + id, nullptr);
1076 } else {
1077 bool needActivate = false;
1078 if (value.userType() == QMetaType::QObjectStar) {
1079 QObject *o = *(QObject *const *)value.data();
1080 needActivate = readPropertyAsQObject(id) != o; // TODO: still correct?
1081 writeProperty(id, o);
1082 } else {
1083 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
1084 if (md) {
1085 const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
1086 needActivate = (!v ||
1087 v->d()->data().userType() != value.userType() ||
1088 v->d()->data() != value);
1089 if (v)
1090 v->removeVmePropertyReference();
1091 md->set(engine, id, engine->newVariantObject(value));
1092 v = static_cast<const QV4::VariantObject *>(md->data() + id);
1093 v->addVmePropertyReference();
1094 }
1095 }
1096
1097 if (needActivate)
1098 activate(object, methodOffset() + id, nullptr);
1099 }
1100}
1101
1102QV4::ReturnedValue QQmlVMEMetaObject::vmeMethod(int index) const
1103{
1104 if (index < methodOffset()) {
1105 Q_ASSERT(parentVMEMetaObject());
1106 return parentVMEMetaObject()->vmeMethod(index);
1107 }
1108 if (!compiledObject)
1109 return QV4::Value::undefinedValue().asReturnedValue();
1110 const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
1111 Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
1112 return method(index - methodOffset() - plainSignals);
1113}
1114
1115// Used by debugger
1116void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function)
1117{
1118 if (index < methodOffset()) {
1119 Q_ASSERT(parentVMEMetaObject());
1120 return parentVMEMetaObject()->setVmeMethod(index, function);
1121 }
1122 if (!compiledObject)
1123 return;
1124 const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
1125 Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
1126
1127 int methodIndex = index - methodOffset() - plainSignals;
1128 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
1129 if (!md)
1130 return;
1131 md->set(engine, methodIndex + compiledObject->nProperties, function);
1132}
1133
1134QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const
1135{
1136 if (index < propOffset()) {
1137 Q_ASSERT(parentVMEMetaObject());
1138 return parentVMEMetaObject()->vmeProperty(index);
1139 }
1140 return readVarProperty(index - propOffset());
1141}
1142
1143void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v)
1144{
1145 if (index < propOffset()) {
1146 Q_ASSERT(parentVMEMetaObject());
1147 parentVMEMetaObject()->setVMEProperty(index, v);
1148 return;
1149 }
1150 return writeVarProperty(index - propOffset(), v);
1151}
1152
1153void QQmlVMEMetaObject::ensureQObjectWrapper()
1154{
1155 Q_ASSERT(cache);
1156 QV4::QObjectWrapper::wrap(engine, object);
1157}
1158
1159void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
1160{
1161 if (engine != markStack->engine)
1162 return;
1163
1164 propertyAndMethodStorage.markOnce(markStack);
1165
1166 if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
1167 parent->mark(markStack);
1168}
1169
1170bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
1171{
1172 Q_ASSERT(compiledObject && (index >= propOffset() + int(compiledObject->nProperties)));
1173
1174 *target = nullptr;
1175 *coreIndex = -1;
1176 *valueTypeIndex = -1;
1177
1178 if (!ctxt)
1179 return false;
1180
1181 const int aliasId = index - propOffset() - compiledObject->nProperties;
1182 const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
1183 *target = ctxt->idValues[aliasData->targetObjectId].data();
1184 if (!*target)
1185 return false;
1186
1187 if (!aliasData->isObjectAlias()) {
1188 QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
1189 *coreIndex = encodedIndex.coreIndex();
1190 *valueTypeIndex = encodedIndex.valueTypeIndex();
1191 }
1192 return true;
1193}
1194
1195void QQmlVMEMetaObject::connectAlias(int aliasId)
1196{
1197 Q_ASSERT(compiledObject);
1198 if (!aliasEndpoints)
1199 aliasEndpoints = new QQmlVMEMetaObjectEndpoint[compiledObject->nAliases];
1200
1201 const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
1202
1203 QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
1204 if (endpoint->metaObject.data()) {
1205 // already connected
1206 Q_ASSERT(endpoint->metaObject.data() == this);
1207 return;
1208 }
1209
1210 endpoint->metaObject = this;
1211 endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
1212 endpoint->tryConnect();
1213}
1214
1215void QQmlVMEMetaObject::connectAliasSignal(int index, bool indexInSignalRange)
1216{
1217 Q_ASSERT(compiledObject);
1218 int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - compiledObject->nProperties;
1219 if (aliasId < 0 || aliasId >= int(compiledObject->nAliases))
1220 return;
1221
1222 connectAlias(aliasId);
1223}
1224
1225/*! \internal
1226 \a index is in the method index range (QMetaMethod::methodIndex()).
1227*/
1228void QQmlVMEMetaObject::activate(QObject *object, int index, void **args)
1229{
1230 QMetaObject::activate(object, signalOffset(), index - methodOffset(), args);
1231}
1232
1233QQmlVMEMetaObject *QQmlVMEMetaObject::getForProperty(QObject *o, int coreIndex)
1234{
1235 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
1236 while (vme && vme->propOffset() > coreIndex)
1237 vme = vme->parentVMEMetaObject();
1238
1239 Q_ASSERT(vme);
1240 return vme;
1241}
1242
1243QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex)
1244{
1245 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
1246 while (vme && vme->methodOffset() > coreIndex)
1247 vme = vme->parentVMEMetaObject();
1248
1249 Q_ASSERT(vme);
1250 return vme;
1251}
1252
1253/*! \internal
1254 \a coreIndex is in the signal index range (see QObjectPrivate::signalIndex()).
1255 This is different from QMetaMethod::methodIndex().
1256*/
1257QQmlVMEMetaObject *QQmlVMEMetaObject::getForSignal(QObject *o, int coreIndex)
1258{
1259 QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
1260 while (vme && vme->signalOffset() > coreIndex)
1261 vme = vme->parentVMEMetaObject();
1262
1263 Q_ASSERT(vme);
1264 return vme;
1265}
1266
1267QQmlVMEVariantQObjectPtr *QQmlVMEMetaObject::getQObjectGuardForProperty(int index) const
1268{
1269 QList<QQmlVMEVariantQObjectPtr *>::ConstIterator it = varObjectGuards.constBegin(), end = varObjectGuards.constEnd();
1270 for ( ; it != end; ++it) {
1271 if ((*it)->m_index == index) {
1272 return *it;
1273 }
1274 }
1275
1276 return nullptr;
1277}
1278
1279QT_END_NAMESPACE
1280