Fix leak introduced in 0853343c33e394f35c31c161b019b2aed17f9256.
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.cpp
index 1e8cfb6..50674fa 100644 (file)
 
 #include "qqmlpropertycache_p.h"
 
-#include "qqmlengine_p.h"
-#include "qqmlbinding_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
 #include <private/qv8engine_p.h>
 
 #include <private/qmetaobject_p.h>
 #include <private/qqmlaccessors_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlrewrite_p.h>
 
 #include <QtCore/qdebug.h>
 
 #include <ctype.h> // for toupper
+#include <limits.h>
+
+#ifdef Q_CC_MSVC
+// nonstandard extension used : zero-sized array in struct/union.
+#  pragma warning( disable : 4200 )
+#endif
 
 Q_DECLARE_METATYPE(QJSValue)
 Q_DECLARE_METATYPE(QQmlV8Handle);
@@ -59,10 +68,18 @@ QT_BEGIN_NAMESPACE
 
 #define Q_INT16_MAX 32767
 
-class QQmlPropertyCacheMethodArguments 
+class QQmlPropertyCacheMethodArguments
 {
 public:
     QQmlPropertyCacheMethodArguments *next;
+
+    //for signal handler rewrites
+    QString *signalParameterStringForJS;
+    int signalParameterCountForJS:30;
+    int parameterError:1;
+    int argumentsValid:1;
+
+    QList<QByteArray> *names;
     int arguments[0];
 };
 
@@ -86,7 +103,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
     return flags;
 }
 
-// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
+// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
 // load
 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
 {
@@ -94,7 +111,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en
 
     QQmlPropertyData::Flags flags;
 
-    if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
+    if (propType == QMetaType::QObjectStar) {
         flags |= QQmlPropertyData::IsQObjectDerived;
     } else if (propType == QMetaType::QVariant) {
         flags |= QQmlPropertyData::IsQVariant;
@@ -106,7 +123,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en
     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
         flags |= QQmlPropertyData::IsV8Handle;
     } else {
-        QQmlMetaType::TypeCategory cat = 
+        QQmlMetaType::TypeCategory cat =
             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
                    : QQmlMetaType::typeCategory(propType);
 
@@ -138,14 +155,14 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
     Q_UNUSED(engine);
 
     coreIndex = p.propertyIndex();
-    notifyIndex = p.notifySignalIndex();
+    notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
     Q_ASSERT(p.revision() <= Q_INT16_MAX);
     revision = p.revision();
 
     flags = fastFlagsForProperty(p);
 
     int type = p.type();
-    if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
+    if (type == QMetaType::QObjectStar) {
         propType = type;
         flags |= QQmlPropertyData::IsQObjectDerived;
     } else if (type == QMetaType::QVariant) {
@@ -163,7 +180,7 @@ void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
 {
     propType = p.userType();
     coreIndex = p.propertyIndex();
-    notifyIndex = p.notifySignalIndex();
+    notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
     Q_ASSERT(p.revision() <= Q_INT16_MAX);
     revision = p.revision();
@@ -185,6 +202,9 @@ void QQmlPropertyData::load(const QMetaMethod &m)
         }
     }
 
+    if (m.attributes() & QMetaMethod::Cloned)
+        flags |= IsCloned;
+
     Q_ASSERT(m.revision() <= Q_INT16_MAX);
     revision = m.revision();
 }
@@ -199,7 +219,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
     propType = QMetaType::Void;
 
     const char *returnType = m.typeName();
-    Q_ASSERT(returnType != 0);
+    if (!returnType)
+        returnType = "\0";
     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
         propTypeName = returnType;
         flags |= NotFullyResolved;
@@ -212,6 +233,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
         }
     }
 
+    if (m.attributes() & QMetaMethod::Cloned)
+        flags |= IsCloned;
+
     Q_ASSERT(m.revision() <= Q_INT16_MAX);
     revision = m.revision();
 }
@@ -220,8 +244,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
 Creates a new empty QQmlPropertyCache.
 */
 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
-: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
-  signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+  signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+  _metaObject(0), argumentsCache(0)
 {
     Q_ASSERT(engine);
 }
@@ -230,8 +255,9 @@ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
 Creates a new QQmlPropertyCache of \a metaObject.
 */
 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
-: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
-  signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+  signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+  _metaObject(0), argumentsCache(0)
 {
     Q_ASSERT(engine);
     Q_ASSERT(metaObject);
@@ -246,6 +272,8 @@ QQmlPropertyCache::~QQmlPropertyCache()
     QQmlPropertyCacheMethodArguments *args = argumentsCache;
     while (args) {
         QQmlPropertyCacheMethodArguments *next = args->next;
+        if (args->signalParameterStringForJS) delete args->signalParameterStringForJS;
+        if (args->names) delete args->names;
         free(args);
         args = next;
     }
@@ -253,8 +281,11 @@ QQmlPropertyCache::~QQmlPropertyCache()
     // We must clear this prior to releasing the parent incase it is a
     // linked hash
     stringCache.clear();
-    if (parent) parent->release();
-    parent = 0;
+    if (_parent) _parent->release();
+
+    if (_ownMetaObject) free((void *)_metaObject);
+    _metaObject = 0;
+    _parent = 0;
     engine = 0;
 }
 
@@ -278,14 +309,15 @@ void QQmlPropertyCache::clear()
 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
 {
     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
-    cache->parent = this;
-    cache->parent->addref();
+    cache->_parent = this;
+    cache->_parent->addref();
     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
-    cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
+    cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
     cache->stringCache.linkAndReserve(stringCache, reserve);
     cache->allowedRevisionCache = allowedRevisionCache;
-    cache->metaObject = metaObject;
+    cache->_metaObject = _metaObject;
+    cache->_defaultPropertyName = _defaultPropertyName;
 
     // We specifically do *NOT* copy the constructor
 
@@ -297,6 +329,269 @@ QQmlPropertyCache *QQmlPropertyCache::copy()
     return copy(0);
 }
 
+QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
+                                                     int signalCount)
+{
+    QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
+    rv->propertyIndexCache.reserve(propertyCount);
+    rv->methodIndexCache.reserve(methodCount);
+    rv->signalHandlerIndexCache.reserve(signalCount);
+    rv->_metaObject = 0;
+
+    return rv;
+}
+
+/*! \internal
+
+    \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+void QQmlPropertyCache::appendProperty(const QString &name,
+                                       quint32 flags, int coreIndex, int propType, int notifyIndex)
+{
+    QQmlPropertyData data;
+    data.propType = propType;
+    data.coreIndex = coreIndex;
+    data.notifyIndex = notifyIndex;
+    data.flags = flags;
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int index = propertyIndexCache.count();
+    propertyIndexCache.append(data);
+
+    setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
+}
+
+void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
+                                       quint32 flags, int coreIndex, int propType, int notifyIndex)
+{
+    QQmlPropertyData data;
+    data.propType = propType;
+    data.coreIndex = coreIndex;
+    data.notifyIndex = notifyIndex;
+    data.flags = flags;
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int index = propertyIndexCache.count();
+    propertyIndexCache.append(data);
+
+    setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
+}
+
+void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
+                                     const int *types, const QList<QByteArray> &names)
+{
+    QQmlPropertyData data;
+    data.propType = QVariant::Invalid;
+    data.coreIndex = coreIndex;
+    data.flags = flags;
+    data.arguments = 0;
+
+    QQmlPropertyData handler = data;
+    handler.flags |= QQmlPropertyData::IsSignalHandler;
+
+    if (types) {
+        int argumentCount = *types;
+        typedef QQmlPropertyCacheMethodArguments A;
+        A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+        ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+        args->argumentsValid = true;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
+        args->names = new QList<QByteArray>(names);
+        args->next = argumentsCache;
+        argumentsCache = args;
+        data.arguments = args;
+    }
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int methodIndex = methodIndexCache.count();
+    methodIndexCache.append(data);
+
+    int signalHandlerIndex = signalHandlerIndexCache.count();
+    signalHandlerIndexCache.append(handler);
+
+    QString handlerName = QLatin1String("on") + name;
+    handlerName[2] = handlerName[2].toUpper();
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+    setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
+                                     const int *types, const QList<QByteArray> &names)
+{
+    QQmlPropertyData data;
+    data.propType = QVariant::Invalid;
+    data.coreIndex = coreIndex;
+    data.flags = flags;
+    data.arguments = 0;
+
+    QQmlPropertyData handler = data;
+    handler.flags |= QQmlPropertyData::IsSignalHandler;
+
+    if (types) {
+        int argumentCount = *types;
+        typedef QQmlPropertyCacheMethodArguments A;
+        A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+        ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+        args->argumentsValid = true;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
+        args->names = new QList<QByteArray>(names);
+        args->next = argumentsCache;
+        argumentsCache = args;
+        data.arguments = args;
+    }
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int methodIndex = methodIndexCache.count();
+    methodIndexCache.append(data);
+
+    int signalHandlerIndex = signalHandlerIndexCache.count();
+    signalHandlerIndexCache.append(handler);
+
+    QString handlerName = QLatin1String("on") + name.toUtf16();
+    handlerName[2] = handlerName[2].toUpper();
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+    setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
+                                     const QList<QByteArray> &names)
+{
+    int argumentCount = names.count();
+
+    QQmlPropertyData data;
+    data.propType = QMetaType::QVariant;
+    data.coreIndex = coreIndex;
+
+    typedef QQmlPropertyCacheMethodArguments A;
+    A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+    args->arguments[0] = argumentCount;
+    for (int ii = 0; ii < argumentCount; ++ii)
+        args->arguments[ii + 1] = QMetaType::QVariant;
+    args->argumentsValid = true;
+    args->signalParameterStringForJS = 0;
+    args->signalParameterCountForJS = 0;
+    args->parameterError = false;
+    args->names = 0;
+    if (argumentCount)
+        args->names = new QList<QByteArray>(names);
+    args->next = argumentsCache;
+    argumentsCache = args;
+    data.arguments = args;
+
+    data.flags = flags;
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int methodIndex = methodIndexCache.count();
+    methodIndexCache.append(data);
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
+                                     const QList<QByteArray> &names)
+{
+    int argumentCount = names.count();
+
+    QQmlPropertyData data;
+    data.propType = QMetaType::QVariant;
+    data.coreIndex = coreIndex;
+
+    typedef QQmlPropertyCacheMethodArguments A;
+    A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+    args->arguments[0] = argumentCount;
+    for (int ii = 0; ii < argumentCount; ++ii)
+        args->arguments[ii + 1] = QMetaType::QVariant;
+    args->argumentsValid = true;
+    args->signalParameterStringForJS = 0;
+    args->signalParameterCountForJS = 0;
+    args->parameterError = false;
+    args->names = 0;
+    if (argumentCount)
+        args->names = new QList<QByteArray>(names);
+    args->next = argumentsCache;
+    argumentsCache = args;
+    data.arguments = args;
+
+    data.flags = flags;
+
+    QQmlPropertyData *old = findNamedProperty(name);
+    if (old)
+        data.markAsOverrideOf(old);
+
+    int methodIndex = methodIndexCache.count();
+    methodIndexCache.append(data);
+
+    setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+}
+
+// Returns this property cache's metaObject.  May be null if it hasn't been created yet.
+const QMetaObject *QQmlPropertyCache::metaObject() const
+{
+    return _metaObject;
+}
+
+// Returns this property cache's metaObject, creating it if necessary.
+const QMetaObject *QQmlPropertyCache::createMetaObject()
+{
+    if (!_metaObject) {
+        _ownMetaObject = true;
+
+        QMetaObjectBuilder builder;
+        toMetaObjectBuilder(builder);
+        builder.setSuperClass(_parent->createMetaObject());
+        _metaObject = builder.toMetaObject();
+    }
+
+    return _metaObject;
+}
+
+// Returns the name of the default property for this cache
+QString QQmlPropertyCache::defaultPropertyName() const
+{
+    return _defaultPropertyName;
+}
+
+QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+{
+    return property(defaultPropertyName(), 0, 0);
+}
+
+QQmlPropertyCache *QQmlPropertyCache::parent() const
+{
+    return _parent;
+}
+
+// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
+// QML
+const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
+{
+    while (_parent && (_metaObject == 0 || _ownMetaObject))
+        return _parent->firstCppMetaObject();
+    return _metaObject;
+}
+
 QQmlPropertyCache *
 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
                                          QQmlPropertyData::Flag propertyFlags,
@@ -327,16 +622,8 @@ QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObje
     return rv;
 }
 
-void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
-                                       QQmlPropertyData::Flag propertyFlags,
-                                       QQmlPropertyData::Flag methodFlags,
-                                       QQmlPropertyData::Flag signalFlags)
-{
-    append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
-}
-
-void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
-                                       int revision, 
+void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
+                                       int revision,
                                        QQmlPropertyData::Flag propertyFlags,
                                        QQmlPropertyData::Flag methodFlags,
                                        QQmlPropertyData::Flag signalFlags)
@@ -344,7 +631,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
     Q_UNUSED(revision);
     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
 
-    this->metaObject = metaObject;
+    _metaObject = metaObject;
 
     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
 
@@ -357,10 +644,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
 
     QQmlAccessorProperties::Properties accessorProperties;
 
-    // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it
-    if (metaObject == &QObject::staticMetaObject) {
-        accessorProperties = QQmlAccessorProperties::properties(metaObject);
-    } else if (classInfoCount) {
+    if (classInfoCount) {
         int classInfoOffset = metaObject->classInfoOffset();
         bool hasFastProperty = false;
         for (int ii = 0; ii < classInfoCount; ++ii) {
@@ -368,7 +652,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
 
             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
                 hasFastProperty = true;
-                break;
+            } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
+                _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
             }
         }
 
@@ -387,34 +672,33 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         }
     }
 
-    // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject
-    // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
-    int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset());
+    //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
+    static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+    static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
+    static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+
+    int methodOffset = metaObject->methodOffset();
     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
 
     // update() should have reserved enough space in the vector that this doesn't cause a realloc
     // and invalidate the stringCache.
     methodIndexCache.resize(methodCount - methodIndexCacheStart);
-    signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
+    signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
     int signalHandlerIndex = signalOffset;
     for (int ii = methodOffset; ii < methodCount; ++ii) {
+        if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
+            continue;
         QMetaMethod m = metaObject->method(ii);
-        if (m.access() == QMetaMethod::Private) 
+        if (m.access() == QMetaMethod::Private)
             continue;
 
         // Extract method name
-        const char *signature;
-        if (QMetaObjectPrivate::get(metaObject)->revision >= 7) {
-            // Safe to use the raw name pointer
-            signature = m.name().constData();
-        } else {
-            // Safe to use the raw signature pointer
-            signature = m.methodSignature().constData();
-        }
-        const char *cptr = signature;
+        // It's safe to keep the raw name pointer
+        Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
+        const char *rawName = m.name().constData();
+        const char *cptr = rawName;
         char utf8 = 0;
-        while (*cptr && *cptr != '(') {
-            Q_ASSERT(*cptr != 0);
+        while (*cptr) {
             utf8 |= *cptr & 0x80;
             ++cptr;
         }
@@ -436,7 +720,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         data->metaObjectOffset = allowedRevisionCache.count() - 1;
 
         if (data->isSignal()) {
-            sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
+            sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
             *sigdata = *data;
             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
         }
@@ -444,21 +728,21 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         QQmlPropertyData *old = 0;
 
         if (utf8) {
-            QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
-            if (QQmlPropertyData **it = stringCache.value(methodName))
-                old = *it;
-            stringCache.insert(methodName, data);
+            QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
+            if (StringCache::mapped_type *it = stringCache.value(methodName))
+                old = it->second;
+            setNamedProperty(methodName, ii, data, (old != 0));
 
             if (data->isSignal()) {
                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
-                stringCache.insert(on, sigdata);
+                setNamedProperty(on, ii, sigdata, (old != 0));
                 ++signalHandlerIndex;
             }
         } else {
-            QHashedCStringRef methodName(signature, cptr - signature);
-            if (QQmlPropertyData **it = stringCache.value(methodName))
-                old = *it;
-            stringCache.insert(methodName, data);
+            QHashedCStringRef methodName(rawName, cptr - rawName);
+            if (StringCache::mapped_type *it = stringCache.value(methodName))
+                old = it->second;
+            setNamedProperty(methodName, ii, data, (old != 0));
 
             if (data->isSignal()) {
                 int length = methodName.length();
@@ -466,13 +750,13 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
                 QVarLengthArray<char, 128> str(length+3);
                 str[0] = 'o';
                 str[1] = 'n';
-                str[2] = toupper(signature[0]);
+                str[2] = toupper(rawName[0]);
                 if (length > 1)
-                    memcpy(&str[3], &signature[1], length - 1);
+                    memcpy(&str[3], &rawName[1], length - 1);
                 str[length + 2] = '\0';
 
                 QHashedString on(QString::fromLatin1(str.data()));
-                stringCache.insert(on, sigdata);
+                setNamedProperty(on, ii, data, (old != 0));
                 ++signalHandlerIndex;
             }
         }
@@ -481,8 +765,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
             // We only overload methods in the same class, exactly like C++
             if (old->isFunction() && old->coreIndex >= methodOffset)
                 data->flags |= QQmlPropertyData::IsOverload;
-            data->overrideIndexIsProperty = !old->isFunction();
-            data->overrideIndex = old->coreIndex;
+
+            data->markAsOverrideOf(old);
         }
     }
 
@@ -510,7 +794,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
         data->lazyLoad(p, engine);
         data->flags |= propertyFlags;
 
-        if (!dynamicMetaObject) 
+        if (!dynamicMetaObject)
             data->flags |= QQmlPropertyData::IsDirect;
 
         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
@@ -520,14 +804,14 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
 
         if (utf8) {
             QHashedString propName(QString::fromUtf8(str, cptr - str));
-            if (QQmlPropertyData **it = stringCache.value(propName))
-                old = *it;
-            stringCache.insert(propName, data);
+            if (StringCache::mapped_type *it = stringCache.value(propName))
+                old = it->second;
+            setNamedProperty(propName, ii, data, (old != 0));
         } else {
             QHashedCStringRef propName(str, cptr - str);
-            if (QQmlPropertyData **it = stringCache.value(propName))
-                old = *it;
-            stringCache.insert(propName, data);
+            if (StringCache::mapped_type *it = stringCache.value(propName))
+                old = it->second;
+            setNamedProperty(propName, ii, data, (old != 0));
         }
 
         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
@@ -540,12 +824,19 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
             data->accessors = accessorProperty->accessors;
             data->accessorData = accessorProperty->data;
         } else if (old) {
-            data->overrideIndexIsProperty = !old->isFunction();
-            data->overrideIndex = old->coreIndex;
+            data->markAsOverrideOf(old);
         }
     }
 }
 
+QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
+{
+    if (p && p->notFullyResolved())
+        resolve(p);
+
+    return p;
+}
+
 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
 {
     Q_ASSERT(data->notFullyResolved());
@@ -565,7 +856,7 @@ void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaO
 
     updateRecur(engine, metaObject->superClass());
 
-    append(engine, metaObject);
+    append(engine, metaObject, -1);
 }
 
 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
@@ -582,7 +873,7 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject
     int sc = metaObjectSignalCount(metaObject);
     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
     methodIndexCache.reserve(mc - methodIndexCacheStart);
-    signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
+    signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
 
     // Reserve enough space in the stringCache for all properties/methods/signals including those
     // cached in a parent cache.
@@ -591,18 +882,48 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject
     updateRecur(engine,metaObject);
 }
 
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QQmlPropertyData *
+QQmlPropertyCache::signal(int index, QQmlPropertyCache **c) const
+{
+    if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+        return 0;
+
+    if (index < signalHandlerIndexCacheStart)
+        return _parent->signal(index, c);
+
+    QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+    if (rv->notFullyResolved()) resolve(rv);
+    Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
+    if (c) *c = const_cast<QQmlPropertyCache *>(this);
+    return rv;
+}
+
+int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
+{
+    if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+        return index;
+
+    if (index < methodIndexCacheStart)
+        return _parent->methodIndexToSignalIndex(index);
+
+    return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
+}
+
 QQmlPropertyData *
 QQmlPropertyCache::property(int index) const
 {
     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
         return 0;
-    
+
     if (index < propertyIndexCacheStart)
-        return parent->property(index);
+        return _parent->property(index);
 
     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
-    if (rv->notFullyResolved()) resolve(rv);
-    return rv;
+    return ensureResolved(rv);
 }
 
 QQmlPropertyData *
@@ -612,35 +933,63 @@ QQmlPropertyCache::method(int index) const
         return 0;
 
     if (index < methodIndexCacheStart)
-        return parent->method(index);
+        return _parent->method(index);
 
     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
-    if (rv->notFullyResolved()) resolve(rv);
-    return rv;
+    return ensureResolved(rv);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedStringRef &str) const
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    QQmlData *data = (object ? QQmlData::get(object) : 0);
+    const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0);
+    return findProperty(it, vmemo, context);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedCStringRef &str) const
+namespace {
+
+inline bool contextHasNoExtensions(QQmlContextData *context)
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    // This context has no extension if its parent is the engine's rootContext,
+    // which has children but no imports
+    return (!context->parent || !context->parent->imports);
 }
 
-QQmlPropertyData *
-QQmlPropertyCache::property(const QString &str) const
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
+{
+    return (prop->isFunction() ? vmemo->methodCount()
+                               : prop->isSignalHandler() ? vmemo->signalCount()
+                                                         : vmemo->propertyCount());
+}
+
+}
+
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
 {
-    QQmlPropertyData **rv = stringCache.value(str);
-    if (rv && (*rv)->notFullyResolved()) resolve(*rv);
-    return rv?*rv:0;
+    StringCache::ConstIterator end = stringCache.end();
+
+    if (it != end) {
+        if (vmemo && context && !contextHasNoExtensions(context)) {
+            // Find the highest property offset known to the supplied context
+            do {
+                if (vmemo->ctxt == context)
+                    break;
+
+                vmemo = vmemo->parentVMEMetaObject();
+            } while (vmemo);
+        }
+
+        do {
+            // Is this property available to this context?
+            const StringCache::mapped_type &property(it.value());
+            if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo)))
+                return ensureResolved(property.second);
+
+            it = stringCache.findNext(it);
+        } while (it != end);
+    }
+
+    return 0;
 }
 
 QString QQmlPropertyData::name(QObject *object)
@@ -666,10 +1015,18 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject)
     }
 }
 
+void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+{
+    overrideIndexIsProperty = !predecessor->isFunction();
+    overrideIndex = predecessor->coreIndex;
+
+    predecessor->flags |= QQmlPropertyData::IsOverridden;
+}
+
 QStringList QQmlPropertyCache::propertyNames() const
 {
     QStringList keys;
-    for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
+    for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
         keys.append(iter.key());
     return keys;
 }
@@ -688,7 +1045,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
     if (scopeIdx != -1) {
         scope = str.left(scopeIdx);
         name = str.mid(scopeIdx + 2);
-    } else { 
+    } else {
         name = str;
     }
     const QMetaObject *meta;
@@ -704,9 +1061,72 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
     return type;
 }
 
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString)
+{
+    QQmlPropertyCache *c = 0;
+    QQmlPropertyData *signalData = signal(index, &c);
+    if (!signalData)
+        return QString();
+
+    typedef QQmlPropertyCacheMethodArguments A;
+
+    if (signalData->arguments) {
+        A *arguments = static_cast<A *>(signalData->arguments);
+        if (arguments->signalParameterStringForJS) {
+            if (count)
+                *count = arguments->signalParameterCountForJS;
+            if (arguments->parameterError) {
+                if (errorString)
+                    *errorString = *arguments->signalParameterStringForJS;
+                return QString();
+            }
+            return *arguments->signalParameterStringForJS;
+        }
+    }
+
+    QList<QByteArray> parameterNameList = signalParameterNames(index);
+
+    if (!signalData->arguments) {
+        int argc = parameterNameList.count();
+        A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+        args->arguments[0] = argc;
+        args->argumentsValid = false;
+        args->signalParameterStringForJS = 0;
+        args->signalParameterCountForJS = 0;
+        args->parameterError = false;
+        args->names = new QList<QByteArray>(parameterNameList);
+        signalData->arguments = args;
+        args->next = c->argumentsCache;
+        c->argumentsCache = args;
+    }
+
+    QQmlRewrite::RewriteSignalHandler rewriter;
+    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+    const QString &parameters = rewriter.createParameterString(parameterNameList,
+                                                               ep->v8engine()->illegalNames());
+
+    bool error = rewriter.hasParameterError();
+    A *arguments = static_cast<A *>(signalData->arguments);
+    arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters);
+    arguments->signalParameterCountForJS = rewriter.parameterCountForJS();
+    if (count)
+        *count = arguments->signalParameterCountForJS;
+    if (error) {
+        arguments->parameterError = true;
+        if (errorString)
+            *errorString = *arguments->signalParameterStringForJS;
+        return QString();
+    }
+    return *arguments->signalParameterStringForJS;
+}
+
 // Returns an array of the arguments for method \a index.  The first entry in the array
 // is the number of arguments.
-int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
+int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
                                                      QVarLengthArray<int, 9> &dummy,
                                                      QByteArray *unknownTypeError)
 {
@@ -721,19 +1141,32 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
 
         while (index < c->methodIndexCacheStart)
-            c = c->parent;
+            c = c->_parent;
 
         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
 
-        if (rv->arguments)  
+        if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid)
             return static_cast<A *>(rv->arguments)->arguments;
 
-        const QMetaObject *metaObject = object->metaObject();
+        const QMetaObject *metaObject = c->createMetaObject();
+        Q_ASSERT(metaObject);
         QMetaMethod m = metaObject->method(index);
 
         int argc = m.parameterCount();
-        A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
-        args->arguments[0] = argc;
+        if (!rv->arguments) {
+            A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+            args->arguments[0] = argc;
+            args->argumentsValid = false;
+            args->signalParameterStringForJS = 0;
+            args->signalParameterCountForJS = 0;
+            args->parameterError = false;
+            args->names = 0;
+            rv->arguments = args;
+            args->next = c->argumentsCache;
+            c->argumentsCache = args;
+        }
+        A *args = static_cast<A *>(rv->arguments);
+
         QList<QByteArray> argTypeNames; // Only loaded if needed
 
         for (int ii = 0; ii < argc; ++ii) {
@@ -751,15 +1184,11 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
             }
             if (type == QMetaType::UnknownType) {
                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
-                free(args);
                 return 0;
             }
             args->arguments[ii + 1] = type;
         }
-
-        rv->arguments = args;
-        args->next = c->argumentsCache;
-        c->argumentsCache = args;
+        args->argumentsValid = true;
         return static_cast<A *>(rv->arguments)->arguments;
 
     } else {
@@ -793,8 +1222,78 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
     }
 }
 
-QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
-                                                         const QString &property)
+// Returns the return type of the method.
+int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
+                                        QByteArray *unknownTypeError)
+{
+    Q_ASSERT(object && data.coreIndex >= 0);
+
+    int type = data.propType;
+
+    const char *propTypeName = 0;
+
+    if (type == QMetaType::UnknownType) {
+        // Find the return type name from the method info
+        QMetaMethod m;
+
+        QQmlData *ddata = QQmlData::get(object, false);
+        if (ddata && ddata->propertyCache) {
+            QQmlPropertyCache *c = ddata->propertyCache;
+            Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+            while (data.coreIndex < c->methodIndexCacheStart)
+                c = c->_parent;
+
+            const QMetaObject *metaObject = c->createMetaObject();
+            Q_ASSERT(metaObject);
+            m = metaObject->method(data.coreIndex);
+        } else {
+            m = object->metaObject()->method(data.coreIndex);
+        }
+
+        type = m.returnType();
+        propTypeName = m.typeName();
+    }
+
+    QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+    if (flags & QMetaType::IsEnumeration) {
+        type = QVariant::Int;
+    } else if (type == QMetaType::UnknownType ||
+               (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+               type != qMetaTypeId<QJSValue>())) {
+        //the UserType clause is to catch registered QFlags
+        type = EnumType(object->metaObject(), propTypeName, type);
+    }
+
+    if (type == QMetaType::UnknownType) {
+        if (unknownTypeError) *unknownTypeError = propTypeName;
+    }
+
+    return type;
+}
+
+int QQmlPropertyCache::originalClone(int index)
+{
+    while (signal(index)->isCloned())
+        --index;
+    return index;
+}
+
+int QQmlPropertyCache::originalClone(QObject *object, int index)
+{
+    QQmlData *data = QQmlData::get(object, false);
+    if (data && data->propertyCache) {
+        QQmlPropertyCache *cache = data->propertyCache;
+        while (cache->signal(index)->isCloned())
+            --index;
+    } else {
+        while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
+            --index;
+    }
+    return index;
+}
+
+QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
 {
     Q_ASSERT(metaObject);
 
@@ -819,11 +1318,15 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
         }
     }
 
+    //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
+    static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+    static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
+    static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+
     int methodCount = metaObject->methodCount();
-    int defaultMethods = QObject::staticMetaObject.methodCount();
-    for (int ii = methodCount - 1; ii >= defaultMethods; --ii) {
-        // >=defaultMethods to block the signals and slots of QObject::staticMetaObject
-        // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
+    for (int ii = methodCount - 1; ii >= 0; --ii) {
+        if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
+            continue;
         QMetaMethod m = metaObject->method(ii);
         if (m.access() == QMetaMethod::Private)
             continue;
@@ -850,34 +1353,31 @@ inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
 
 template<typename T>
 QQmlPropertyData *
-qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
-                                  const T &name, QQmlPropertyData &local)
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
+                          QQmlContextData *context, QQmlPropertyData &local)
 {
     QQmlPropertyCache *cache = 0;
 
-    if (engine) {
-        QQmlData *ddata = QQmlData::get(obj);
+    QQmlData *ddata = QQmlData::get(obj, false);
 
-        if (ddata && ddata->propertyCache) {
-            cache = ddata->propertyCache;
-        } else if (engine) {
-            QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
-            cache = ep->cache(obj);
-            if (cache) {
-                ddata = QQmlData::get(obj, true);
-                cache->addref();
-                ddata->propertyCache = cache;
-            }
+    if (ddata && ddata->propertyCache) {
+        cache = ddata->propertyCache;
+    } else if (engine) {
+        QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+        cache = ep->cache(obj);
+        if (cache) {
+            ddata = QQmlData::get(obj, true);
+            cache->addref();
+            ddata->propertyCache = cache;
         }
     }
 
     QQmlPropertyData *rv = 0;
 
     if (cache) {
-        rv = cache->property(name);
+        rv = cache->property(name, obj, context);
     } else {
-        local = qQmlPropertyCacheCreate(obj->metaObject(),
-                                                qQmlPropertyCacheToString(name));
+        local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
         if (local.isValid())
             rv = &local;
     }
@@ -886,17 +1386,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
 }
 
 QQmlPropertyData *
-QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
-                                    const QHashedV8String &name, QQmlPropertyData &local)
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
+                            QQmlContextData *context, QQmlPropertyData &local)
 {
-    return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
+    return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
 }
 
 QQmlPropertyData *
 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
-                                    const QString &name, QQmlPropertyData &local)
+                                    const QString &name, QQmlContextData *context, QQmlPropertyData &local)
 {
-    return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
+    return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
 }
 
 static inline const QMetaObjectPrivate *priv(const uint* data)
@@ -907,4 +1407,198 @@ bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
 }
 
+const char *QQmlPropertyCache::className() const
+{
+    if (!_ownMetaObject && _metaObject)
+        return _metaObject->className();
+    else
+        return _dynamicClassName.constData();
+}
+
+void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
+{
+    struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
+                                 const QPair<QString, QQmlPropertyData *> &rhs) {
+        return lhs.second->coreIndex < rhs.second->coreIndex;
+    } };
+
+    struct Insert { static void in(QQmlPropertyCache *This,
+                                   QList<QPair<QString, QQmlPropertyData *> > &properties,
+                                   QList<QPair<QString, QQmlPropertyData *> > &methods,
+                                   StringCache::ConstIterator iter, QQmlPropertyData *data) {
+        if (data->isSignalHandler())
+            return;
+
+        if (data->isFunction()) {
+            if (data->coreIndex < This->methodIndexCacheStart)
+                return;
+
+            QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+            // Overrides can cause the entry to already exist
+            if (!methods.contains(entry)) methods.append(entry);
+
+            data = This->overrideData(data);
+            if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
+        } else {
+            if (data->coreIndex < This->propertyIndexCacheStart)
+                return;
+
+            QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+            // Overrides can cause the entry to already exist
+            if (!properties.contains(entry)) properties.append(entry);
+
+            data = This->overrideData(data);
+            if (data) Insert::in(This, properties, methods, iter, data);
+        }
+
+    } };
+
+    builder.setClassName(_dynamicClassName);
+
+    QList<QPair<QString, QQmlPropertyData *> > properties;
+    QList<QPair<QString, QQmlPropertyData *> > methods;
+
+    for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+        Insert::in(this, properties, methods, iter, iter.value().second);
+
+    Q_ASSERT(properties.count() == propertyIndexCache.count());
+    Q_ASSERT(methods.count() == methodIndexCache.count());
+
+    qSort(properties.begin(), properties.end(), Sort::lt);
+    qSort(methods.begin(), methods.end(), Sort::lt);
+
+    for (int ii = 0; ii < properties.count(); ++ii) {
+        QQmlPropertyData *data = properties.at(ii).second;
+
+        int notifierId = -1;
+        if (data->notifyIndex != -1)
+            notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
+
+        QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
+                                                            QMetaType::typeName(data->propType),
+                                                            notifierId);
+
+        property.setReadable(true);
+        property.setWritable(data->isWritable());
+        property.setResettable(data->isResettable());
+    }
+
+    for (int ii = 0; ii < methods.count(); ++ii) {
+        QQmlPropertyData *data = methods.at(ii).second;
+
+        QByteArray returnType;
+        if (data->propType != 0)
+            returnType = QMetaType::typeName(data->propType);
+
+        QByteArray signature = methods.at(ii).first.toUtf8() + "(";
+
+        QQmlPropertyCacheMethodArguments *arguments = 0;
+        if (data->hasArguments()) {
+            arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
+            Q_ASSERT(arguments->argumentsValid);
+            for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
+                if (ii != 0) signature.append(",");
+                signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
+            }
+        }
+
+        signature.append(")");
+
+        QMetaMethodBuilder method;
+        if (data->isSignal()) {
+            method = builder.addSignal(signature);
+        } else {
+            method = builder.addSlot(signature);
+        }
+        method.setAccess(QMetaMethod::Protected);
+
+        if (arguments && arguments->names)
+            method.setParameterNames(*arguments->names);
+
+        if (!returnType.isEmpty())
+            method.setReturnType(returnType);
+    }
+
+    if (!_defaultPropertyName.isEmpty()) {
+        QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
+        if (dp && dp->coreIndex >= propertyIndexCacheStart) {
+            Q_ASSERT(!dp->isFunction());
+            builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
+        }
+    }
+}
+
+/*! \internal
+    \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+    This is different from QMetaMethod::methodIndex().
+*/
+QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
+{
+    QQmlPropertyData *signalData = signal(index);
+    if (signalData && signalData->hasArguments()) {
+        QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments;
+        if (args && args->names)
+            return *args->names;
+        const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
+        return method.parameterNames();
+    }
+    return QList<QByteArray>();
+}
+
+// Returns true if \a from is assignable to a property of type \a to
+bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
+{
+    Q_ASSERT(!from.isNull() && !to.isNull());
+
+    struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
+        return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+    } };
+
+    const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
+    if (tom == &QObject::staticMetaObject) return true;
+
+    if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
+        QQmlPropertyCache *fromp = from._m.asT1();
+        QQmlPropertyCache *top = to._m.asT1();
+
+        while (fromp) {
+            if (fromp == top) return true;
+            fromp = fromp->parent();
+        }
+    } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
+        QQmlPropertyCache *fromp = from._m.asT1();
+
+        while (fromp) {
+            const QMetaObject *fromm = fromp->metaObject();
+            if (fromm && I::equal(fromm, tom)) return true;
+            fromp = fromp->parent();
+        }
+    } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
+        const QMetaObject *fromm = from._m.asT2();
+
+        if (!tom) return false;
+
+        while (fromm) {
+            if (I::equal(fromm, tom)) return true;
+            fromm = fromm->superClass();
+        }
+    } else { // QMetaObject -> QMetaObject
+        const QMetaObject *fromm = from._m.asT2();
+
+        while (fromm) {
+            if (I::equal(fromm, tom)) return true;
+            fromm = fromm->superClass();
+        }
+    }
+
+    return false;
+}
+
+QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
+{
+    if (_m.isNull()) return 0;
+    if (_m.isT1()) return _m.asT1();
+    else return e->cache(_m.asT2());
+}
+
 QT_END_NAMESPACE