Ensure that variant property references keep QObjects alive
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlvmemetaobject.cpp
index 7ea89a4..2434ef0 100644 (file)
 #include "qqmlpropertyvalueinterceptor_p.h"
 
 #include <private/qv8variantresource_p.h>
+#include <private/qqmlglobal_p.h>
 
 Q_DECLARE_METATYPE(QJSValue);
 
 QT_BEGIN_NAMESPACE
 
+QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
+    : QQmlGuard<QObject>(0), m_target(0), m_index(-1)
+{
+}
+
+QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
+{
+}
+
+void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
+{
+    if (m_target && m_index >= 0)
+        m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
+}
+
+void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index)
+{
+    m_target = target;
+    m_index = index;
+    setObject(obj);
+}
+
 class QQmlVMEVariant
 {
 public:
@@ -65,6 +88,7 @@ public:
     inline const void *dataPtr() const;
     inline void *dataPtr();
     inline int dataType() const;
+    inline size_t dataSize() const;
 
     inline QObject *asQObject();
     inline const QVariant &asQVariant();
@@ -73,27 +97,32 @@ public:
     inline double asDouble();
     inline const QString &asQString();
     inline const QUrl &asQUrl();
-    inline const QColor &asQColor();
     inline const QTime &asQTime();
     inline const QDate &asQDate();
     inline const QDateTime &asQDateTime();
+    inline const QRectF &asQRectF();
     inline const QJSValue &asQJSValue();
 
-    inline void setValue(QObject *);
+    inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index);
     inline void setValue(const QVariant &);
     inline void setValue(int);
     inline void setValue(bool);
     inline void setValue(double);
     inline void setValue(const QString &);
     inline void setValue(const QUrl &);
-    inline void setValue(const QColor &);
     inline void setValue(const QTime &);
     inline void setValue(const QDate &);
     inline void setValue(const QDateTime &);
+    inline void setValue(const QRectF &);
     inline void setValue(const QJSValue &);
+
+    inline void setDataType(int t);
+
+    inline void ensureValueType(int);
+
 private:
     int type;
-    void *data[4]; // Large enough to hold all types
+    void *data[8]; // Large enough to hold all types
 
     inline void cleanup();
 };
@@ -102,7 +131,7 @@ class QQmlVMEMetaObjectEndpoint : public QQmlNotifierEndpoint
 {
 public:
     QQmlVMEMetaObjectEndpoint();
-    static void vmecallback(QQmlNotifierEndpoint *);
+    static void vmecallback(QQmlNotifierEndpoint *, void **);
     void tryConnect();
 
     QFlagPointer<QQmlVMEMetaObject> metaObject;
@@ -127,7 +156,7 @@ void QQmlVMEVariant::cleanup()
                type == QMetaType::Double) {
         type = QVariant::Invalid;
     } else if (type == QMetaType::QObjectStar) {
-        ((QQmlGuard<QObject>*)dataPtr())->~QQmlGuard<QObject>();
+        ((QQmlVMEVariantQObjectPtr*)dataPtr())->~QQmlVMEVariantQObjectPtr();
         type = QVariant::Invalid;
     } else if (type == QMetaType::QString) {
         ((QString *)dataPtr())->~QString();
@@ -135,9 +164,6 @@ void QQmlVMEVariant::cleanup()
     } else if (type == QMetaType::QUrl) {
         ((QUrl *)dataPtr())->~QUrl();
         type = QVariant::Invalid;
-    } else if (type == QMetaType::QColor) {
-        ((QColor *)dataPtr())->~QColor();
-        type = QVariant::Invalid;
     } else if (type == QMetaType::QTime) {
         ((QTime *)dataPtr())->~QTime();
         type = QVariant::Invalid;
@@ -147,14 +173,20 @@ void QQmlVMEVariant::cleanup()
     } else if (type == QMetaType::QDateTime) {
         ((QDateTime *)dataPtr())->~QDateTime();
         type = QVariant::Invalid;
+    } else if (type == QMetaType::QRectF) {
+        ((QRectF *)dataPtr())->~QRectF();
+        type = QVariant::Invalid;
     } else if (type == qMetaTypeId<QVariant>()) {
         ((QVariant *)dataPtr())->~QVariant();
         type = QVariant::Invalid;
     } else if (type == qMetaTypeId<QJSValue>()) {
         ((QJSValue *)dataPtr())->~QJSValue();
         type = QVariant::Invalid;
+    } else {
+        if (QQml_valueTypeProvider()->destroyValueType(type, dataPtr(), dataSize())) {
+            type = QVariant::Invalid;
+        }
     }
-
 }
 
 int QQmlVMEVariant::dataType() const
@@ -172,10 +204,15 @@ void *QQmlVMEVariant::dataPtr()
     return &data;
 }
 
+size_t QQmlVMEVariant::dataSize() const
+{
+    return sizeof(data);
+}
+
 QObject *QQmlVMEVariant::asQObject() 
 {
-    if (type != QMetaType::QObjectStar) 
-        setValue((QObject *)0);
+    if (type != QMetaType::QObjectStar)
+        setValue((QObject *)0, 0, -1);
 
     return *(QQmlGuard<QObject> *)(dataPtr());
 }
@@ -228,14 +265,6 @@ const QUrl &QQmlVMEVariant::asQUrl()
     return *(QUrl *)(dataPtr());
 }
 
-const QColor &QQmlVMEVariant::asQColor() 
-{
-    if (type != QMetaType::QColor)
-        setValue(QColor());
-
-    return *(QColor *)(dataPtr());
-}
-
 const QTime &QQmlVMEVariant::asQTime() 
 {
     if (type != QMetaType::QTime)
@@ -260,6 +289,14 @@ const QDateTime &QQmlVMEVariant::asQDateTime()
     return *(QDateTime *)(dataPtr());
 }
 
+const QRectF &QQmlVMEVariant::asQRectF()
+{
+    if (type != QMetaType::QRectF)
+        setValue(QRectF());
+
+    return *(QRectF *)(dataPtr());
+}
+
 const QJSValue &QQmlVMEVariant::asQJSValue()
 {
     if (type != qMetaTypeId<QJSValue>())
@@ -268,14 +305,14 @@ const QJSValue &QQmlVMEVariant::asQJSValue()
     return *(QJSValue *)(dataPtr());
 }
 
-void QQmlVMEVariant::setValue(QObject *v)
+void QQmlVMEVariant::setValue(QObject *v, QQmlVMEMetaObject *target, int index)
 {
     if (type != QMetaType::QObjectStar) {
         cleanup();
         type = QMetaType::QObjectStar;
-        new (dataPtr()) QQmlGuard<QObject>();
+        new (dataPtr()) QQmlVMEVariantQObjectPtr;
     }
-    *(QQmlGuard<QObject>*)(dataPtr()) = v;
+    reinterpret_cast<QQmlVMEVariantQObjectPtr*>(dataPtr())->setGuardedValue(v, target, index);
 }
 
 void QQmlVMEVariant::setValue(const QVariant &v)
@@ -338,17 +375,6 @@ void QQmlVMEVariant::setValue(const QUrl &v)
     }
 }
 
-void QQmlVMEVariant::setValue(const QColor &v)
-{
-    if (type != QMetaType::QColor) {
-        cleanup();
-        type = QMetaType::QColor;
-        new (dataPtr()) QColor(v);
-    } else {
-        *(QColor *)(dataPtr()) = v;
-    }
-}
-
 void QQmlVMEVariant::setValue(const QTime &v)
 {
     if (type != QMetaType::QTime) {
@@ -382,6 +408,17 @@ void QQmlVMEVariant::setValue(const QDateTime &v)
     }
 }
 
+void QQmlVMEVariant::setValue(const QRectF &v)
+{
+    if (type != QMetaType::QRectF) {
+        cleanup();
+        type = QMetaType::QRectF;
+        new (dataPtr()) QRectF(v);
+    } else {
+        *(QRectF *)(dataPtr()) = v;
+    }
+}
+
 void QQmlVMEVariant::setValue(const QJSValue &v)
 {
     if (type != qMetaTypeId<QJSValue>()) {
@@ -393,12 +430,26 @@ void QQmlVMEVariant::setValue(const QJSValue &v)
     }
 }
 
+void QQmlVMEVariant::setDataType(int t)
+{
+    type = t;
+}
+
+void QQmlVMEVariant::ensureValueType(int t)
+{
+    if (type != t) {
+        cleanup();
+        type = t;
+        QQml_valueTypeProvider()->initValueType(t, dataPtr(), dataSize());
+    }
+}
+
 QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
 {
-    callback = &vmecallback;
+    setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint);
 }
 
-void QQmlVMEMetaObjectEndpoint::vmecallback(QQmlNotifierEndpoint *e)
+void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **)
 {
     QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e);
     vmee->tryConnect();
@@ -410,8 +461,8 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
 
     if (metaObject.flag()) {
         // This is actually notify
-        int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
-        QMetaObject::activate(metaObject->object, sigIdx, 0);
+        int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount;
+        metaObject->activate(metaObject->object, sigIdx, 0);
     } else {
         QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
         if (!d->isObjectAlias()) {
@@ -420,60 +471,79 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
             if (!target)
                 return;
 
-            QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
-            if (prop.hasNotifySignal())
-                connect(target, prop.notifySignalIndex());
+            if (d->notifySignal != -1)
+                connect(target, d->notifySignal, ctxt->engine);
         }
 
         metaObject.setFlag();
     }
 }
 
-QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
-                                                     const QMetaObject *other, 
-                                                     const QQmlVMEMetaData *meta,
-                                                     QQmlCompiledData *cdata)
-: QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
-  ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), data(0),
-  aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
-  v8methods(0), parent(0)
+QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o)
 {
-    compiledData->addref();
+    if (!hasAssignedMetaObjectData) {
+        *static_cast<QMetaObject *>(this) = *cache->createMetaObject();
+
+        if (parent.isT1())
+            this->d.superdata = parent.asT1()->toDynamicMetaObject(o);
+        else
+            this->d.superdata = parent.asT2();
 
-    *static_cast<QMetaObject *>(this) = *other;
-    this->d.superdata = obj->metaObject();
+        hasAssignedMetaObjectData = true;
+    }
+
+    return this;
+}
 
+QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
+                                     QQmlPropertyCache *cache,
+                                     const QQmlVMEMetaData *meta)
+: QV8GCCallback::Node(GcPrologueCallback), object(obj),
+  ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta),
+  hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1),
+  varPropertiesInitialized(false), interceptors(0), v8methods(0)
+{
     QObjectPrivate *op = QObjectPrivate::get(obj);
-    if (op->metaObject)
-        parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
-    op->metaObject = this;
 
-    propOffset = QAbstractDynamicMetaObject::propertyOffset();
-    methodOffset = QAbstractDynamicMetaObject::methodOffset();
+    if (op->metaObject) parent = op->metaObject;
+    else parent = obj->metaObject();
+
+    op->metaObject = this;
+    QQmlData::get(obj)->hasVMEMetaObject = true;
 
     data = new QQmlVMEVariant[metaData->propertyCount - metaData->varPropertyCount];
 
     aConnected.resize(metaData->aliasCount);
     int list_type = qMetaTypeId<QQmlListProperty<QObject> >();
+    int qobject_type = qMetaTypeId<QObject*>();
+    int variant_type = qMetaTypeId<QVariant>();
+    bool needsGcCallback = (metaData->varPropertyCount > 0);
 
     // ### Optimize
     for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
         int t = (metaData->propertyData() + ii)->propertyType;
         if (t == list_type) {
-            listProperties.append(List(methodOffset + ii));
+            listProperties.append(List(methodOffset() + ii, this));
             data[ii].setValue(listProperties.count() - 1);
-        } 
+        } else if (!needsGcCallback && (t == qobject_type || t == variant_type)) {
+            needsGcCallback = true;
+        }
     }
 
     firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
-    if (metaData->varPropertyCount)
+
+    // both var properties and variant properties can keep references to
+    // other QObjects, and var properties can also keep references to
+    // JavaScript objects.  If we have any properties, we need to hook
+    // the gc() to ensure that references keep objects alive as needed.
+    if (needsGcCallback) {
         QV8GCCallback::addGcCallbackNode(this);
+    }
 }
 
 QQmlVMEMetaObject::~QQmlVMEMetaObject()
 {
-    compiledData->release();
-    delete parent;
+    if (parent.isT1()) parent.asT1()->objectDestroyed(object);
     delete [] data;
     delete [] aliasEndpoints;
 
@@ -489,15 +559,15 @@ QQmlVMEMetaObject::~QQmlVMEMetaObject()
 int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
 {
     int id = _id;
-    if(c == QMetaObject::WriteProperty) {
-        int flags = *reinterpret_cast<int*>(a[3]);
-        if (!(flags & QQmlPropertyPrivate::BypassInterceptor)
-            && !aInterceptors.isEmpty()
-            && aInterceptors.testBit(id)) {
-            QPair<int, QQmlPropertyValueInterceptor*> pair = interceptors.value(id);
-            int valueIndex = pair.first;
-            QQmlPropertyValueInterceptor *vi = pair.second;
-            int type = property(id).userType();
+    if (c == QMetaObject::WriteProperty && interceptors &&
+       !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) {
+
+        for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+            if (vi->m_coreIndex != id)
+                continue;
+
+            int valueIndex = vi->m_valueTypeCoreIndex;
+            int type = QQmlData::get(object)->propertyCache->property(id)->propType;
 
             if (type != QVariant::Invalid) {
                 if (valueIndex != -1) {
@@ -521,8 +591,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
         }
     }
     if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
-        if (id >= propOffset) {
-            id -= propOffset;
+        if (id >= propOffset()) {
+            id -= propOffset();
 
             if (id < metaData->propertyCount) {
                int t = (metaData->propertyData() + id)->propertyType;
@@ -565,15 +635,15 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                         case QVariant::Url:
                             *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
                             break;
-                        case QVariant::Color:
-                            *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor();
-                            break;
                         case QVariant::Date:
                             *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
                             break;
                         case QVariant::DateTime:
                             *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
                             break;
+                        case QVariant::RectF:
+                            *reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF();
+                            break;
                         case QMetaType::QObjectStar:
                             *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
                             break;
@@ -581,6 +651,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                             *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
                             break;
                         default:
+                            QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), t, a[0]);
                             break;
                         }
                         if (t == qMetaTypeId<QQmlListProperty<QObject> >()) {
@@ -615,10 +686,6 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                             needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
                             data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
                             break;
-                        case QVariant::Color:
-                            needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor();
-                            data[id].setValue(*reinterpret_cast<QColor *>(a[0]));
-                            break;
                         case QVariant::Date:
                             needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
                             data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
@@ -627,14 +694,21 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                             needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
                             data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
                             break;
+                        case QVariant::RectF:
+                            needActivate = *reinterpret_cast<QRectF *>(a[0]) != data[id].asQRectF();
+                            data[id].setValue(*reinterpret_cast<QRectF *>(a[0]));
+                            break;
                         case QMetaType::QObjectStar:
                             needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
-                            data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
+                            data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id);
                             break;
                         case QMetaType::QVariant:
                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
                             break;
                         default:
+                            data[id].ensureValueType(t);
+                            needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr());
+                            QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
                             break;
                         }
                     }
@@ -642,7 +716,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                 }
 
                 if (c == QMetaObject::WriteProperty && needActivate) {
-                    activate(object, methodOffset + id, 0);
+                    activate(object, methodOffset() + id, 0);
                 }
 
                 return -1;
@@ -711,13 +785,13 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
 
     } else if(c == QMetaObject::InvokeMetaMethod) {
 
-        if (id >= methodOffset) {
+        if (id >= methodOffset()) {
 
-            id -= methodOffset;
+            id -= methodOffset();
             int plainSignals = metaData->signalCount + metaData->propertyCount +
                                metaData->aliasCount;
             if (id < plainSignals) {
-                QMetaObject::activate(object, _id, a);
+                activate(object, _id, a);
                 return -1;
             }
 
@@ -738,7 +812,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                     // performance reasons; see QTBUG-24064) and thus compilation will have failed.
                     QQmlError e;
                     e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")).
-                                     arg(QLatin1String(QMetaObject::method(_id).signature())));
+                                     arg(QLatin1String(QMetaObject::method(_id).methodSignature().constData())));
                     ep->warning(e);
                     return -1; // The dynamic method with that id is not available.
                 }
@@ -777,14 +851,19 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
         }
     }
 
-    if (parent)
-        return parent->metaCall(c, _id, a);
+    if (parent.isT1())
+        return parent.asT1()->metaCall(object, c, _id, a);
     else
         return object->qt_metacall(c, _id, a);
 }
 
 v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
 {
+    if (!ctxt || !ctxt->isValid()) {
+        qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
+        return v8::Handle<v8::Function>();
+    }
+
     if (!v8methods) 
         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
 
@@ -810,15 +889,17 @@ v8::Handle<v8::Value> QQmlVMEMetaObject::readVarProperty(int id)
 {
     Q_ASSERT(id >= firstVarPropertyIndex);
 
-    ensureVarPropertiesAllocated();
-    return varProperties->Get(id - firstVarPropertyIndex);
+    if (ensureVarPropertiesAllocated())
+        return varProperties->Get(id - firstVarPropertyIndex);
+    return v8::Handle<v8::Value>();
 }
 
 QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
 {
     if (id >= firstVarPropertyIndex) {
-        ensureVarPropertiesAllocated();
-        return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+        if (ensureVarPropertiesAllocated())
+            return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+        return QVariant();
     } else {
         if (data[id].dataType() == QMetaType::QObjectStar) {
             return QVariant::fromValue(data[id].asQObject());
@@ -831,7 +912,8 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
 void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
 {
     Q_ASSERT(id >= firstVarPropertyIndex);
-    ensureVarPropertiesAllocated();
+    if (!ensureVarPropertiesAllocated())
+        return;
 
     // Importantly, if the current value is a scarce resource, we need to ensure that it
     // gets automatically released by the engine if no other references to it exist.
@@ -854,13 +936,14 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
 
     // Write the value and emit change signal as appropriate.
     varProperties->Set(id - firstVarPropertyIndex, value);
-    activate(object, methodOffset + id, 0);
+    activate(object, methodOffset() + id, 0);
 }
 
 void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
 {
     if (id >= firstVarPropertyIndex) {
-        ensureVarPropertiesAllocated();
+        if (!ensureVarPropertiesAllocated())
+            return;
 
         // Importantly, if the current value is a scarce resource, we need to ensure that it
         // gets automatically released by the engine if no other references to it exist.
@@ -886,13 +969,13 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
         QVariant currentValue = readPropertyAsVariant(id);
         varProperties->Set(id - firstVarPropertyIndex, newv);
         if ((currentValue.userType() != value.userType() || currentValue != value))
-            activate(object, methodOffset + id, 0);
+            activate(object, methodOffset() + id, 0);
     } else {
         bool needActivate = false;
         if (value.userType() == QMetaType::QObjectStar) {
-            QObject *o = qvariant_cast<QObject *>(value);
+            QObject *o = *(QObject **)value.data();
             needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
-            data[id].setValue(qvariant_cast<QObject *>(value));
+            data[id].setValue(o, this, id);
         } else {
             needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
                             data[id].asQVariant().userType() != value.userType() ||
@@ -901,20 +984,20 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
         }
 
         if (needActivate)
-            activate(object, methodOffset + id, 0);
+            activate(object, methodOffset() + id, 0);
     }
 }
 
 void QQmlVMEMetaObject::listChanged(int id)
 {
-    activate(object, methodOffset + id, 0);
+    activate(object, methodOffset() + id, 0);
 }
 
 void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
 {
     List *list = static_cast<List *>(prop->data);
     list->append(o);
-    QMetaObject::activate(prop->object, list->notifyIndex, 0);
+    list->mo->activate(prop->object, list->notifyIndex, 0);
 }
 
 int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop)
@@ -931,28 +1014,28 @@ void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
 {
     List *list = static_cast<List *>(prop->data);
     list->clear();
-    QMetaObject::activate(prop->object, list->notifyIndex, 0);
+    list->mo->activate(prop->object, list->notifyIndex, 0);
 }
 
 void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor)
 {
-    if (aInterceptors.isEmpty())
-        aInterceptors.resize(propertyCount() + metaData->propertyCount);
-    aInterceptors.setBit(index);
-    interceptors.insert(index, qMakePair(valueIndex, interceptor));
+    interceptor->m_coreIndex = index;
+    interceptor->m_valueTypeCoreIndex = valueIndex;
+    interceptor->m_next = interceptors;
+    interceptors = interceptor;
 }
 
 int QQmlVMEMetaObject::vmeMethodLineNumber(int index)
 {
-    if (index < methodOffset) {
-        Q_ASSERT(parent);
-        return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
+    if (index < methodOffset()) {
+        Q_ASSERT(parent.isT1());
+        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethodLineNumber(index);
     }
 
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
-    Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+    Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
 
-    int rawIndex = index - methodOffset - plainSignals;
+    int rawIndex = index - methodOffset() - plainSignals;
 
     QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
     return data->lineNumber;
@@ -960,29 +1043,29 @@ int QQmlVMEMetaObject::vmeMethodLineNumber(int index)
 
 v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
 {
-    if (index < methodOffset) {
-        Q_ASSERT(parent);
-        return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethod(index);
+    if (index < methodOffset()) {
+        Q_ASSERT(parent.isT1());
+        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethod(index);
     }
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
-    Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
-    return method(index - methodOffset - plainSignals);
+    Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
+    return method(index - methodOffset() - plainSignals);
 }
 
 // Used by debugger
 void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
 {
-    if (index < methodOffset) {
-        Q_ASSERT(parent);
-        return static_cast<QQmlVMEMetaObject *>(parent)->setVmeMethod(index, value);
+    if (index < methodOffset()) {
+        Q_ASSERT(parent.isT1());
+        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVmeMethod(index, value);
     }
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
-    Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+    Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
 
     if (!v8methods) 
         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
 
-    int methodIndex = index - methodOffset - plainSignals;
+    int methodIndex = index - methodOffset() - plainSignals;
     if (!v8methods[methodIndex].IsEmpty()) 
         qPersistentDispose(v8methods[methodIndex]);
     v8methods[methodIndex] = value;
@@ -990,27 +1073,34 @@ void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> val
 
 v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
 {
-    if (index < propOffset) {
-        Q_ASSERT(parent);
-        return static_cast<QQmlVMEMetaObject *>(parent)->vmeProperty(index);
+    if (index < propOffset()) {
+        Q_ASSERT(parent.isT1());
+        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeProperty(index);
     }
-    return readVarProperty(index - propOffset);
+    return readVarProperty(index - propOffset());
 }
 
 void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
 {
-    if (index < propOffset) {
-        Q_ASSERT(parent);
-        static_cast<QQmlVMEMetaObject *>(parent)->setVMEProperty(index, v);
+    if (index < propOffset()) {
+        Q_ASSERT(parent.isT1());
+        static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVMEProperty(index, v);
         return;
     }
-    return writeVarProperty(index - propOffset, v);
+    return writeVarProperty(index - propOffset(), v);
 }
 
-void QQmlVMEMetaObject::ensureVarPropertiesAllocated()
+bool QQmlVMEMetaObject::ensureVarPropertiesAllocated()
 {
     if (!varPropertiesInitialized)
         allocateVarPropertiesArray();
+
+    // in some situations, the QObject's v8object (and associated v8 data,
+    // such as the varProperties array) will have been cleaned up, but the
+    // QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
+    // In this situation, the varProperties handle will be (and should remain)
+    // empty.
+    return !varProperties.IsEmpty();
 }
 
 // see also: QV8GCCallback::garbageCollectorPrologueCallback()
@@ -1042,15 +1132,32 @@ void QQmlVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node)
 {
     QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(node);
     Q_ASSERT(vmemo);
-    if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty() || !vmemo->ctxt || !vmemo->ctxt->engine)
+
+    if (!vmemo->ctxt || !vmemo->ctxt->engine)
         return;
     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(vmemo->ctxt->engine);
+
+    // add references created by VMEVariant properties
+    int maxDataIdx = vmemo->metaData->propertyCount - vmemo->metaData->varPropertyCount;
+    for (int ii = 0; ii < maxDataIdx; ++ii) { // XXX TODO: optimise?
+        if (vmemo->data[ii].dataType() == QMetaType::QObjectStar) {
+            // possible QObject reference.
+            QObject *ref = vmemo->data[ii].asQObject();
+            if (ref) {
+                ep->v8engine()->addRelationshipForGC(vmemo->object, ref);
+            }
+        }
+    }
+
+    // add references created by var properties
+    if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty())
+        return;
     ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
 }
 
 bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
 {
-    Q_ASSERT(index >= propOffset + metaData->propertyCount);
+    Q_ASSERT(index >= propOffset() + metaData->propertyCount);
 
     *target = 0;
     *coreIndex = -1;
@@ -1059,7 +1166,7 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
     if (!ctxt)
         return false;
 
-    QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
+    QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount);
     QQmlContext *context = ctxt->asQQmlContext();
     QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
 
@@ -1100,11 +1207,39 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
 
 void QQmlVMEMetaObject::connectAliasSignal(int index)
 {
-    int aliasId = (index - methodOffset) - metaData->propertyCount;
+    int aliasId = (index - methodOffset()) - metaData->propertyCount;
     if (aliasId < 0 || aliasId >= metaData->aliasCount)
         return;
 
     connectAlias(aliasId);
 }
 
+void QQmlVMEMetaObject::activate(QObject *object, int index, void **args)
+{
+    int signalOffset = cache->signalOffset();
+    int methodOffset = cache->methodOffset();
+
+    QMetaObject::activate(object, methodOffset, signalOffset, index - methodOffset, args);
+}
+
+QQmlVMEMetaObject *QQmlVMEMetaObject::getForProperty(QObject *o, int coreIndex)
+{
+    QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
+    while (vme->propOffset() > coreIndex) {
+        Q_ASSERT(vme->parent.isT1());
+        vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
+    }
+    return vme;
+}
+
+QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex)
+{
+    QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
+    while (vme->methodOffset() > coreIndex) {
+        Q_ASSERT(vme->parent.isT1());
+        vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
+    }
+    return vme;
+}
+
 QT_END_NAMESPACE