Check dynamic slot function for nullness before evaluation
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativevmemetaobject.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativevmemetaobject_p.h"
43
44
45 #include "qdeclarative.h"
46 #include <private/qdeclarativerefcount_p.h>
47 #include "qdeclarativeexpression.h"
48 #include "qdeclarativeexpression_p.h"
49 #include "qdeclarativecontext_p.h"
50 #include "qdeclarativebinding_p.h"
51 #include "qdeclarativepropertyvalueinterceptor_p.h"
52
53 #include <private/qv8variantresource_p.h>
54
55 Q_DECLARE_METATYPE(QJSValue);
56
57 QT_BEGIN_NAMESPACE
58
59 class QDeclarativeVMEVariant
60 {
61 public:
62     inline QDeclarativeVMEVariant();
63     inline ~QDeclarativeVMEVariant();
64
65     inline const void *dataPtr() const;
66     inline void *dataPtr();
67     inline int dataType() const;
68
69     inline QObject *asQObject();
70     inline const QVariant &asQVariant();
71     inline int asInt();
72     inline bool asBool();
73     inline double asDouble();
74     inline const QString &asQString();
75     inline const QUrl &asQUrl();
76     inline const QColor &asQColor();
77     inline const QTime &asQTime();
78     inline const QDate &asQDate();
79     inline const QDateTime &asQDateTime();
80     inline const QJSValue &asQJSValue();
81
82     inline void setValue(QObject *);
83     inline void setValue(const QVariant &);
84     inline void setValue(int);
85     inline void setValue(bool);
86     inline void setValue(double);
87     inline void setValue(const QString &);
88     inline void setValue(const QUrl &);
89     inline void setValue(const QColor &);
90     inline void setValue(const QTime &);
91     inline void setValue(const QDate &);
92     inline void setValue(const QDateTime &);
93     inline void setValue(const QJSValue &);
94 private:
95     int type;
96     void *data[4]; // Large enough to hold all types
97
98     inline void cleanup();
99 };
100
101 class QDeclarativeVMEMetaObjectEndpoint : public QDeclarativeNotifierEndpoint
102 {
103 public:
104     QDeclarativeVMEMetaObjectEndpoint();
105     static void vmecallback(QDeclarativeNotifierEndpoint *);
106     void tryConnect();
107
108     QFlagPointer<QDeclarativeVMEMetaObject> metaObject;
109 };
110
111
112 QDeclarativeVMEVariant::QDeclarativeVMEVariant()
113 : type(QVariant::Invalid)
114 {
115 }
116
117 QDeclarativeVMEVariant::~QDeclarativeVMEVariant()
118 {
119     cleanup();
120 }
121
122 void QDeclarativeVMEVariant::cleanup()
123 {
124     if (type == QVariant::Invalid) {
125     } else if (type == QMetaType::Int ||
126                type == QMetaType::Bool ||
127                type == QMetaType::Double) {
128         type = QVariant::Invalid;
129     } else if (type == QMetaType::QObjectStar) {
130         ((QDeclarativeGuard<QObject>*)dataPtr())->~QDeclarativeGuard<QObject>();
131         type = QVariant::Invalid;
132     } else if (type == QMetaType::QString) {
133         ((QString *)dataPtr())->~QString();
134         type = QVariant::Invalid;
135     } else if (type == QMetaType::QUrl) {
136         ((QUrl *)dataPtr())->~QUrl();
137         type = QVariant::Invalid;
138     } else if (type == QMetaType::QColor) {
139         ((QColor *)dataPtr())->~QColor();
140         type = QVariant::Invalid;
141     } else if (type == QMetaType::QTime) {
142         ((QTime *)dataPtr())->~QTime();
143         type = QVariant::Invalid;
144     } else if (type == QMetaType::QDate) {
145         ((QDate *)dataPtr())->~QDate();
146         type = QVariant::Invalid;
147     } else if (type == QMetaType::QDateTime) {
148         ((QDateTime *)dataPtr())->~QDateTime();
149         type = QVariant::Invalid;
150     } else if (type == qMetaTypeId<QVariant>()) {
151         ((QVariant *)dataPtr())->~QVariant();
152         type = QVariant::Invalid;
153     } else if (type == qMetaTypeId<QJSValue>()) {
154         ((QJSValue *)dataPtr())->~QJSValue();
155         type = QVariant::Invalid;
156     }
157
158 }
159
160 int QDeclarativeVMEVariant::dataType() const
161 {
162     return type;
163 }
164
165 const void *QDeclarativeVMEVariant::dataPtr() const
166 {
167     return &data;
168 }
169
170 void *QDeclarativeVMEVariant::dataPtr() 
171 {
172     return &data;
173 }
174
175 QObject *QDeclarativeVMEVariant::asQObject() 
176 {
177     if (type != QMetaType::QObjectStar) 
178         setValue((QObject *)0);
179
180     return *(QDeclarativeGuard<QObject> *)(dataPtr());
181 }
182
183 const QVariant &QDeclarativeVMEVariant::asQVariant() 
184 {
185     if (type != QMetaType::QVariant)
186         setValue(QVariant());
187
188     return *(QVariant *)(dataPtr());
189 }
190
191 int QDeclarativeVMEVariant::asInt() 
192 {
193     if (type != QMetaType::Int)
194         setValue(int(0));
195
196     return *(int *)(dataPtr());
197 }
198
199 bool QDeclarativeVMEVariant::asBool() 
200 {
201     if (type != QMetaType::Bool)
202         setValue(bool(false));
203
204     return *(bool *)(dataPtr());
205 }
206
207 double QDeclarativeVMEVariant::asDouble() 
208 {
209     if (type != QMetaType::Double)
210         setValue(double(0));
211
212     return *(double *)(dataPtr());
213 }
214
215 const QString &QDeclarativeVMEVariant::asQString() 
216 {
217     if (type != QMetaType::QString)
218         setValue(QString());
219
220     return *(QString *)(dataPtr());
221 }
222
223 const QUrl &QDeclarativeVMEVariant::asQUrl() 
224 {
225     if (type != QMetaType::QUrl)
226         setValue(QUrl());
227
228     return *(QUrl *)(dataPtr());
229 }
230
231 const QColor &QDeclarativeVMEVariant::asQColor() 
232 {
233     if (type != QMetaType::QColor)
234         setValue(QColor());
235
236     return *(QColor *)(dataPtr());
237 }
238
239 const QTime &QDeclarativeVMEVariant::asQTime() 
240 {
241     if (type != QMetaType::QTime)
242         setValue(QTime());
243
244     return *(QTime *)(dataPtr());
245 }
246
247 const QDate &QDeclarativeVMEVariant::asQDate() 
248 {
249     if (type != QMetaType::QDate)
250         setValue(QDate());
251
252     return *(QDate *)(dataPtr());
253 }
254
255 const QDateTime &QDeclarativeVMEVariant::asQDateTime() 
256 {
257     if (type != QMetaType::QDateTime)
258         setValue(QDateTime());
259
260     return *(QDateTime *)(dataPtr());
261 }
262
263 const QJSValue &QDeclarativeVMEVariant::asQJSValue()
264 {
265     if (type != qMetaTypeId<QJSValue>())
266         setValue(QJSValue());
267
268     return *(QJSValue *)(dataPtr());
269 }
270
271 void QDeclarativeVMEVariant::setValue(QObject *v)
272 {
273     if (type != QMetaType::QObjectStar) {
274         cleanup();
275         type = QMetaType::QObjectStar;
276         new (dataPtr()) QDeclarativeGuard<QObject>();
277     }
278     *(QDeclarativeGuard<QObject>*)(dataPtr()) = v;
279 }
280
281 void QDeclarativeVMEVariant::setValue(const QVariant &v)
282 {
283     if (type != qMetaTypeId<QVariant>()) {
284         cleanup();
285         type = qMetaTypeId<QVariant>();
286         new (dataPtr()) QVariant(v);
287     } else {
288         *(QVariant *)(dataPtr()) = v;
289     }
290 }
291
292 void QDeclarativeVMEVariant::setValue(int v)
293 {
294     if (type != QMetaType::Int) {
295         cleanup();
296         type = QMetaType::Int;
297     }
298     *(int *)(dataPtr()) = v;
299 }
300
301 void QDeclarativeVMEVariant::setValue(bool v)
302 {
303     if (type != QMetaType::Bool) {
304         cleanup();
305         type = QMetaType::Bool;
306     }
307     *(bool *)(dataPtr()) = v;
308 }
309
310 void QDeclarativeVMEVariant::setValue(double v)
311 {
312     if (type != QMetaType::Double) {
313         cleanup();
314         type = QMetaType::Double;
315     }
316     *(double *)(dataPtr()) = v;
317 }
318
319 void QDeclarativeVMEVariant::setValue(const QString &v)
320 {
321     if (type != QMetaType::QString) {
322         cleanup();
323         type = QMetaType::QString;
324         new (dataPtr()) QString(v);
325     } else {
326         *(QString *)(dataPtr()) = v;
327     }
328 }
329
330 void QDeclarativeVMEVariant::setValue(const QUrl &v)
331 {
332     if (type != QMetaType::QUrl) {
333         cleanup();
334         type = QMetaType::QUrl;
335         new (dataPtr()) QUrl(v);
336     } else {
337         *(QUrl *)(dataPtr()) = v;
338     }
339 }
340
341 void QDeclarativeVMEVariant::setValue(const QColor &v)
342 {
343     if (type != QMetaType::QColor) {
344         cleanup();
345         type = QMetaType::QColor;
346         new (dataPtr()) QColor(v);
347     } else {
348         *(QColor *)(dataPtr()) = v;
349     }
350 }
351
352 void QDeclarativeVMEVariant::setValue(const QTime &v)
353 {
354     if (type != QMetaType::QTime) {
355         cleanup();
356         type = QMetaType::QTime;
357         new (dataPtr()) QTime(v);
358     } else {
359         *(QTime *)(dataPtr()) = v;
360     }
361 }
362
363 void QDeclarativeVMEVariant::setValue(const QDate &v)
364 {
365     if (type != QMetaType::QDate) {
366         cleanup();
367         type = QMetaType::QDate;
368         new (dataPtr()) QDate(v);
369     } else {
370         *(QDate *)(dataPtr()) = v;
371     }
372 }
373
374 void QDeclarativeVMEVariant::setValue(const QDateTime &v)
375 {
376     if (type != QMetaType::QDateTime) {
377         cleanup();
378         type = QMetaType::QDateTime;
379         new (dataPtr()) QDateTime(v);
380     } else {
381         *(QDateTime *)(dataPtr()) = v;
382     }
383 }
384
385 void QDeclarativeVMEVariant::setValue(const QJSValue &v)
386 {
387     if (type != qMetaTypeId<QJSValue>()) {
388         cleanup();
389         type = qMetaTypeId<QJSValue>();
390         new (dataPtr()) QJSValue(v);
391     } else {
392         *(QJSValue *)(dataPtr()) = v;
393     }
394 }
395
396 QDeclarativeVMEMetaObjectEndpoint::QDeclarativeVMEMetaObjectEndpoint()
397 {
398     callback = &vmecallback;
399 }
400
401 void QDeclarativeVMEMetaObjectEndpoint::vmecallback(QDeclarativeNotifierEndpoint *e)
402 {
403     QDeclarativeVMEMetaObjectEndpoint *vmee = static_cast<QDeclarativeVMEMetaObjectEndpoint*>(e);
404     vmee->tryConnect();
405 }
406
407 void QDeclarativeVMEMetaObjectEndpoint::tryConnect()
408 {
409     if (metaObject.flag())
410         return;
411
412     int aliasId = this - metaObject->aliasEndpoints;
413
414     QDeclarativeVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
415     if (!d->isObjectAlias()) {
416         QDeclarativeContextData *ctxt = metaObject->ctxt;
417         QObject *target = ctxt->idValues[d->contextIdx].data();
418         if (!target)
419             return;
420
421         QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
422         if (prop.hasNotifySignal()) {
423             int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
424             QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(),
425                                                  metaObject->object, sigIdx);
426         }
427     }
428
429     metaObject.setFlag();
430 }
431
432 QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj,
433                                                      const QMetaObject *other, 
434                                                      const QDeclarativeVMEMetaData *meta,
435                                                      QDeclarativeCompiledData *cdata)
436 : QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
437   ctxt(QDeclarativeData::get(obj, true)->outerContext), metaData(meta), data(0),
438   aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
439   v8methods(0), parent(0)
440 {
441     compiledData->addref();
442
443     *static_cast<QMetaObject *>(this) = *other;
444     this->d.superdata = obj->metaObject();
445
446     QObjectPrivate *op = QObjectPrivate::get(obj);
447     if (op->metaObject)
448         parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
449     op->metaObject = this;
450
451     propOffset = QAbstractDynamicMetaObject::propertyOffset();
452     methodOffset = QAbstractDynamicMetaObject::methodOffset();
453
454     data = new QDeclarativeVMEVariant[metaData->propertyCount - metaData->varPropertyCount];
455
456     aConnected.resize(metaData->aliasCount);
457     int list_type = qMetaTypeId<QDeclarativeListProperty<QObject> >();
458
459     // ### Optimize
460     for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
461         int t = (metaData->propertyData() + ii)->propertyType;
462         if (t == list_type) {
463             listProperties.append(List(methodOffset + ii));
464             data[ii].setValue(listProperties.count() - 1);
465         } 
466     }
467
468     firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
469     if (metaData->varPropertyCount)
470         QV8GCCallback::addGcCallbackNode(this);
471 }
472
473 QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
474 {
475     compiledData->release();
476     delete parent;
477     delete [] data;
478     delete [] aliasEndpoints;
479
480     for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
481         qPersistentDispose(v8methods[ii]);
482     }
483
484     if (metaData->varPropertyCount)
485         qPersistentDispose(varProperties); // if not weak, will not have been cleaned up by the callback.
486 }
487
488 int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
489 {
490     int id = _id;
491     if(c == QMetaObject::WriteProperty) {
492         int flags = *reinterpret_cast<int*>(a[3]);
493         if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor)
494             && !aInterceptors.isEmpty()
495             && aInterceptors.testBit(id)) {
496             QPair<int, QDeclarativePropertyValueInterceptor*> pair = interceptors.value(id);
497             int valueIndex = pair.first;
498             QDeclarativePropertyValueInterceptor *vi = pair.second;
499             int type = property(id).userType();
500
501             if (type != QVariant::Invalid) {
502                 if (valueIndex != -1) {
503                     QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0;
504                     QDeclarativeValueType *valueType = 0;
505                     if (ep) valueType = ep->valueTypes[type];
506                     else valueType = QDeclarativeValueTypeFactory::valueType(type);
507                     Q_ASSERT(valueType);
508
509                     valueType->setValue(QVariant(type, a[0]));
510                     QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
511                     vi->write(valueProp.read(valueType));
512
513                     if (!ep) delete valueType;
514                     return -1;
515                 } else {
516                     vi->write(QVariant(type, a[0]));
517                     return -1;
518                 }
519             }
520         }
521     }
522     if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
523         if (id >= propOffset) {
524             id -= propOffset;
525
526             if (id < metaData->propertyCount) {
527                int t = (metaData->propertyData() + id)->propertyType;
528                 bool needActivate = false;
529
530                 if (id >= firstVarPropertyIndex) {
531                     Q_ASSERT(t == QMetaType::QVariant);
532                     // the context can be null if accessing var properties from cpp after re-parenting an item.
533                     QDeclarativeEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QDeclarativeEnginePrivate::get(ctxt->engine);
534                     QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
535                     if (v8e) {
536                         v8::HandleScope handleScope;
537                         v8::Context::Scope contextScope(v8e->context());
538                         if (c == QMetaObject::ReadProperty) {
539                             *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
540                         } else if (c == QMetaObject::WriteProperty) {
541                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
542                         }
543                     } else if (c == QMetaObject::ReadProperty) {
544                         // if the context was disposed, we just return an invalid variant from read.
545                         *reinterpret_cast<QVariant *>(a[0]) = QVariant();
546                     }
547
548                 } else {
549
550                     if (c == QMetaObject::ReadProperty) {
551                         switch(t) {
552                         case QVariant::Int:
553                             *reinterpret_cast<int *>(a[0]) = data[id].asInt();
554                             break;
555                         case QVariant::Bool:
556                             *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
557                             break;
558                         case QVariant::Double:
559                             *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
560                             break;
561                         case QVariant::String:
562                             *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
563                             break;
564                         case QVariant::Url:
565                             *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
566                             break;
567                         case QVariant::Color:
568                             *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor();
569                             break;
570                         case QVariant::Date:
571                             *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
572                             break;
573                         case QVariant::DateTime:
574                             *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
575                             break;
576                         case QMetaType::QObjectStar:
577                             *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
578                             break;
579                         case QMetaType::QVariant:
580                             *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
581                             break;
582                         default:
583                             break;
584                         }
585                         if (t == qMetaTypeId<QDeclarativeListProperty<QObject> >()) {
586                             int listIndex = data[id].asInt();
587                             const List *list = &listProperties.at(listIndex);
588                             *reinterpret_cast<QDeclarativeListProperty<QObject> *>(a[0]) = 
589                                 QDeclarativeListProperty<QObject>(object, (void *)list,
590                                                                   list_append, list_count, list_at, 
591                                                                   list_clear);
592                         }
593
594                     } else if (c == QMetaObject::WriteProperty) {
595
596                         switch(t) {
597                         case QVariant::Int:
598                             needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
599                             data[id].setValue(*reinterpret_cast<int *>(a[0]));
600                             break;
601                         case QVariant::Bool:
602                             needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
603                             data[id].setValue(*reinterpret_cast<bool *>(a[0]));
604                             break;
605                         case QVariant::Double:
606                             needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
607                             data[id].setValue(*reinterpret_cast<double *>(a[0]));
608                             break;
609                         case QVariant::String:
610                             needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
611                             data[id].setValue(*reinterpret_cast<QString *>(a[0]));
612                             break;
613                         case QVariant::Url:
614                             needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
615                             data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
616                             break;
617                         case QVariant::Color:
618                             needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor();
619                             data[id].setValue(*reinterpret_cast<QColor *>(a[0]));
620                             break;
621                         case QVariant::Date:
622                             needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
623                             data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
624                             break;
625                         case QVariant::DateTime:
626                             needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
627                             data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
628                             break;
629                         case QMetaType::QObjectStar:
630                             needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
631                             data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
632                             break;
633                         case QMetaType::QVariant:
634                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
635                             break;
636                         default:
637                             break;
638                         }
639                     }
640
641                 }
642
643                 if (c == QMetaObject::WriteProperty && needActivate) {
644                     activate(object, methodOffset + id, 0);
645                 }
646
647                 return -1;
648             }
649
650             id -= metaData->propertyCount;
651
652             if (id < metaData->aliasCount) {
653
654                 QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id;
655
656                 if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) 
657                         *reinterpret_cast<void **>(a[0]) = 0;
658
659                 if (!ctxt) return -1;
660
661                 QDeclarativeContext *context = ctxt->asQDeclarativeContext();
662                 QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
663
664                 QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
665                 if (!target) 
666                     return -1;
667
668                 connectAlias(id);
669
670                 if (d->isObjectAlias()) {
671                     *reinterpret_cast<QObject **>(a[0]) = target;
672                     return -1;
673                 } 
674                 
675                 // Remove binding (if any) on write
676                 if(c == QMetaObject::WriteProperty) {
677                     int flags = *reinterpret_cast<int*>(a[3]);
678                     if (flags & QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite) {
679                         QDeclarativeData *targetData = QDeclarativeData::get(target);
680                         if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
681                             QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
682                             if (binding) binding->destroy();
683                         }
684                     }
685                 }
686                 
687                 if (d->isValueTypeAlias()) {
688                     // Value type property
689                     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
690
691                     QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()];
692                     Q_ASSERT(valueType);
693
694                     valueType->read(target, d->propertyIndex());
695                     int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
696                     
697                     if (c == QMetaObject::WriteProperty)
698                         valueType->write(target, d->propertyIndex(), 0x00);
699
700                     return rv;
701
702                 } else {
703                     return QMetaObject::metacall(target, c, d->propertyIndex(), a);
704                 }
705
706             }
707             return -1;
708
709         }
710
711     } else if(c == QMetaObject::InvokeMetaMethod) {
712
713         if (id >= methodOffset) {
714
715             id -= methodOffset;
716             int plainSignals = metaData->signalCount + metaData->propertyCount +
717                                metaData->aliasCount;
718             if (id < plainSignals) {
719                 QMetaObject::activate(object, _id, a);
720                 return -1;
721             }
722
723             id -= plainSignals;
724
725             if (id < metaData->methodCount) {
726                 if (!ctxt->engine)
727                     return -1; // We can't run the method
728
729                 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
730                 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
731
732                 v8::Handle<v8::Function> function = method(id);
733                 if (function.IsEmpty()) {
734                     // The function was not compiled.  There are some exceptional cases which the
735                     // expression rewriter does not rewrite properly (e.g., \r-terminated lines
736                     // are not rewritten correctly but this bug is deemed out-of-scope to fix for
737                     // performance reasons; see QTBUG-24064) and thus compilation will have failed.
738                     QDeclarativeError e;
739                     e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")).arg(QMetaObject::method(_id).signature()));
740                     ep->warning(e);
741                     return -1; // The dynamic method with that id is not available.
742                 }
743
744                 QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
745
746                 v8::HandleScope handle_scope;
747                 v8::Context::Scope scope(ep->v8engine()->context());
748                 v8::Handle<v8::Value> *args = 0;
749
750                 if (data->parameterCount) {
751                     args = new v8::Handle<v8::Value>[data->parameterCount];
752                     for (int ii = 0; ii < data->parameterCount; ++ii) 
753                         args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
754                 }
755
756                 v8::TryCatch try_catch;
757
758                 v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args);
759
760                 QVariant rv;
761                 if (try_catch.HasCaught()) {
762                     QDeclarativeError error;
763                     QDeclarativeExpressionPrivate::exceptionToError(try_catch.Message(), error);
764                     if (error.isValid())
765                         ep->warning(error);
766                     if (a[0]) *(QVariant *)a[0] = QVariant();
767                 } else {
768                     if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
769                 }
770
771                 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
772                 return -1;
773             }
774             return -1;
775         }
776     }
777
778     if (parent)
779         return parent->metaCall(c, _id, a);
780     else
781         return object->qt_metacall(c, _id, a);
782 }
783
784 v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index)
785 {
786     if (!v8methods) 
787         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
788
789     if (v8methods[index].IsEmpty()) {
790         QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
791
792         const QChar *body = 
793             (const QChar *)(((const char*)metaData) + data->bodyOffset);
794
795         QString code = QString::fromRawData(body, data->bodyLength);
796
797         // XXX We should evaluate all methods in a single big script block to 
798         // improve the call time between dynamic methods defined on the same
799         // object
800         v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, code, ctxt->url.toString(),
801                                                                        data->lineNumber);
802     }
803
804     return v8methods[index];
805 }
806
807 v8::Handle<v8::Value> QDeclarativeVMEMetaObject::readVarProperty(int id)
808 {
809     Q_ASSERT(id >= firstVarPropertyIndex);
810
811     ensureVarPropertiesAllocated();
812     return varProperties->Get(id - firstVarPropertyIndex);
813 }
814
815 QVariant QDeclarativeVMEMetaObject::readPropertyAsVariant(int id)
816 {
817     if (id >= firstVarPropertyIndex) {
818         ensureVarPropertiesAllocated();
819         return QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
820     } else {
821         if (data[id].dataType() == QMetaType::QObjectStar) {
822             return QVariant::fromValue(data[id].asQObject());
823         } else {
824             return data[id].asQVariant();
825         }
826     }
827 }
828
829 void QDeclarativeVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
830 {
831     Q_ASSERT(id >= firstVarPropertyIndex);
832     ensureVarPropertiesAllocated();
833
834     // Importantly, if the current value is a scarce resource, we need to ensure that it
835     // gets automatically released by the engine if no other references to it exist.
836     v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
837     if (oldv->IsObject()) {
838         QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
839         if (r) {
840             r->removeVmePropertyReference();
841         }
842     }
843
844     // And, if the new value is a scarce resource, we need to ensure that it does not get
845     // automatically released by the engine until no other references to it exist.
846     if (value->IsObject()) {
847         QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(value));
848         if (r) {
849             r->addVmePropertyReference();
850         }
851     }
852
853     // Write the value and emit change signal as appropriate.
854     varProperties->Set(id - firstVarPropertyIndex, value);
855     activate(object, methodOffset + id, 0);
856 }
857
858 void QDeclarativeVMEMetaObject::writeProperty(int id, const QVariant &value)
859 {
860     if (id >= firstVarPropertyIndex) {
861         ensureVarPropertiesAllocated();
862
863         // Importantly, if the current value is a scarce resource, we need to ensure that it
864         // gets automatically released by the engine if no other references to it exist.
865         v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
866         if (oldv->IsObject()) {
867             QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
868             if (r) {
869                 r->removeVmePropertyReference();
870             }
871         }
872
873         // And, if the new value is a scarce resource, we need to ensure that it does not get
874         // automatically released by the engine until no other references to it exist.
875         v8::Handle<v8::Value> newv = QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
876         if (newv->IsObject()) {
877             QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(newv));
878             if (r) {
879                 r->addVmePropertyReference();
880             }
881         }
882
883         // Write the value and emit change signal as appropriate.
884         QVariant currentValue = readPropertyAsVariant(id);
885         varProperties->Set(id - firstVarPropertyIndex, newv);
886         if ((currentValue.userType() != value.userType() || currentValue != value))
887             activate(object, methodOffset + id, 0);
888     } else {
889         bool needActivate = false;
890         if (value.userType() == QMetaType::QObjectStar) {
891             QObject *o = qvariant_cast<QObject *>(value);
892             needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
893             data[id].setValue(qvariant_cast<QObject *>(value));
894         } else {
895             needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
896                             data[id].asQVariant().userType() != value.userType() ||
897                             data[id].asQVariant() != value);
898             data[id].setValue(value);
899         }
900
901         if (needActivate)
902             activate(object, methodOffset + id, 0);
903     }
904 }
905
906 void QDeclarativeVMEMetaObject::listChanged(int id)
907 {
908     activate(object, methodOffset + id, 0);
909 }
910
911 void QDeclarativeVMEMetaObject::list_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
912 {
913     List *list = static_cast<List *>(prop->data);
914     list->append(o);
915     QMetaObject::activate(prop->object, list->notifyIndex, 0);
916 }
917
918 int QDeclarativeVMEMetaObject::list_count(QDeclarativeListProperty<QObject> *prop)
919 {
920     return static_cast<List *>(prop->data)->count();
921 }
922
923 QObject *QDeclarativeVMEMetaObject::list_at(QDeclarativeListProperty<QObject> *prop, int index)
924 {
925     return static_cast<List *>(prop->data)->at(index);
926 }
927
928 void QDeclarativeVMEMetaObject::list_clear(QDeclarativeListProperty<QObject> *prop)
929 {
930     List *list = static_cast<List *>(prop->data);
931     list->clear();
932     QMetaObject::activate(prop->object, list->notifyIndex, 0);
933 }
934
935 void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor)
936 {
937     if (aInterceptors.isEmpty())
938         aInterceptors.resize(propertyCount() + metaData->propertyCount);
939     aInterceptors.setBit(index);
940     interceptors.insert(index, qMakePair(valueIndex, interceptor));
941 }
942
943 int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index)
944 {
945     if (index < methodOffset) {
946         Q_ASSERT(parent);
947         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
948     }
949
950     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
951     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
952
953     int rawIndex = index - methodOffset - plainSignals;
954
955     QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
956     return data->lineNumber;
957 }
958
959 v8::Handle<v8::Function> QDeclarativeVMEMetaObject::vmeMethod(int index)
960 {
961     if (index < methodOffset) {
962         Q_ASSERT(parent);
963         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethod(index);
964     }
965     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
966     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
967     return method(index - methodOffset - plainSignals);
968 }
969
970 // Used by debugger
971 void QDeclarativeVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
972 {
973     if (index < methodOffset) {
974         Q_ASSERT(parent);
975         return static_cast<QDeclarativeVMEMetaObject *>(parent)->setVmeMethod(index, value);
976     }
977     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
978     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
979
980     if (!v8methods) 
981         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
982
983     int methodIndex = index - methodOffset - plainSignals;
984     if (!v8methods[methodIndex].IsEmpty()) 
985         qPersistentDispose(v8methods[methodIndex]);
986     v8methods[methodIndex] = value;
987 }
988
989 v8::Handle<v8::Value> QDeclarativeVMEMetaObject::vmeProperty(int index)
990 {
991     if (index < propOffset) {
992         Q_ASSERT(parent);
993         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeProperty(index);
994     }
995     return readVarProperty(index - propOffset);
996 }
997
998 void QDeclarativeVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
999 {
1000     if (index < propOffset) {
1001         Q_ASSERT(parent);
1002         static_cast<QDeclarativeVMEMetaObject *>(parent)->setVMEProperty(index, v);
1003         return;
1004     }
1005     return writeVarProperty(index - propOffset, v);
1006 }
1007
1008 void QDeclarativeVMEMetaObject::ensureVarPropertiesAllocated()
1009 {
1010     if (!varPropertiesInitialized)
1011         allocateVarPropertiesArray();
1012 }
1013
1014 // see also: QV8GCCallback::garbageCollectorPrologueCallback()
1015 void QDeclarativeVMEMetaObject::allocateVarPropertiesArray()
1016 {
1017     v8::HandleScope handleScope;
1018     v8::Context::Scope cs(QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->context());
1019     varProperties = qPersistentNew(v8::Array::New(metaData->varPropertyCount));
1020     varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback);
1021     varPropertiesInitialized = true;
1022 }
1023
1024 /*
1025    The "var" properties are stored in a v8::Array which will be strong persistent if the object has cpp-ownership
1026    and the root QObject in the parent chain does not have JS-ownership.  In the weak persistent handle case,
1027    this callback will dispose the handle when the v8object which owns the lifetime of the var properties array
1028    is cleared as a result of all other handles to that v8object being released.
1029    See QV8GCCallback::garbageCollectorPrologueCallback() for more information.
1030  */
1031 void QDeclarativeVMEMetaObject::VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
1032 {
1033     QDeclarativeVMEMetaObject *vmemo = static_cast<QDeclarativeVMEMetaObject*>(parameter);
1034     Q_ASSERT(vmemo);
1035     qPersistentDispose(object);
1036     vmemo->varProperties.Clear();
1037 }
1038
1039 void QDeclarativeVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node)
1040 {
1041     QDeclarativeVMEMetaObject *vmemo = static_cast<QDeclarativeVMEMetaObject*>(node);
1042     Q_ASSERT(vmemo);
1043     if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty() || !vmemo->ctxt || !vmemo->ctxt->engine)
1044         return;
1045     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(vmemo->ctxt->engine);
1046     ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
1047 }
1048
1049 bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
1050 {
1051     Q_ASSERT(index >= propOffset + metaData->propertyCount);
1052
1053     *target = 0;
1054     *coreIndex = -1;
1055     *valueTypeIndex = -1;
1056
1057     if (!ctxt)
1058         return false;
1059
1060     QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
1061     QDeclarativeContext *context = ctxt->asQDeclarativeContext();
1062     QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
1063
1064     *target = ctxtPriv->data->idValues[d->contextIdx].data();
1065     if (!*target)
1066         return false;
1067
1068     if (d->isObjectAlias()) {
1069     } else if (d->isValueTypeAlias()) {
1070         *coreIndex = d->propertyIndex();
1071         *valueTypeIndex = d->valueTypeIndex();
1072     } else {
1073         *coreIndex = d->propertyIndex();
1074     }
1075
1076     return true;
1077 }
1078
1079 void QDeclarativeVMEMetaObject::connectAlias(int aliasId)
1080 {
1081     if (!aConnected.testBit(aliasId)) {
1082
1083         if (!aliasEndpoints)
1084             aliasEndpoints = new QDeclarativeVMEMetaObjectEndpoint[metaData->aliasCount];
1085
1086         aConnected.setBit(aliasId);
1087
1088         QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
1089
1090         QDeclarativeVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
1091         endpoint->metaObject = this;
1092
1093         endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
1094
1095         endpoint->tryConnect();
1096     }
1097 }
1098
1099 void QDeclarativeVMEMetaObject::connectAliasSignal(int index)
1100 {
1101     int aliasId = (index - methodOffset) - metaData->propertyCount;
1102     if (aliasId < 0 || aliasId >= metaData->aliasCount)
1103         return;
1104
1105     connectAlias(aliasId);
1106 }
1107
1108 QT_END_NAMESPACE