9165f890c7aa9c02a96b9ac6802f6e5bc446a0f9
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.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 QtQml 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 "qqmlpropertycache_p.h"
43
44 #include <private/qqmlengine_p.h>
45 #include <private/qqmlbinding_p.h>
46 #include <private/qqmlvmemetaobject_p.h>
47 #include <private/qv8engine_p.h>
48
49 #include <private/qmetaobject_p.h>
50 #include <private/qqmlaccessors_p.h>
51 #include <private/qmetaobjectbuilder_p.h>
52 #include <private/qqmlrewrite_p.h>
53
54 #include <QtCore/qdebug.h>
55
56 #include <ctype.h> // for toupper
57 #include <limits.h>
58
59 #ifdef Q_CC_MSVC
60 // nonstandard extension used : zero-sized array in struct/union.
61 #  pragma warning( disable : 4200 )
62 #endif
63
64 Q_DECLARE_METATYPE(QJSValue)
65 Q_DECLARE_METATYPE(QQmlV8Handle);
66
67 QT_BEGIN_NAMESPACE
68
69 #define Q_INT16_MAX 32767
70
71 class QQmlPropertyCacheMethodArguments
72 {
73 public:
74     QQmlPropertyCacheMethodArguments *next;
75
76     //for signal handler rewrites
77     QString *signalParameterStringForJS;
78     int signalParameterCountForJS:30;
79     int parameterError:1;
80     int argumentsValid:1;
81
82     QList<QByteArray> *names;
83     int arguments[0];
84 };
85
86 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
87 // to load
88 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
89 {
90     QQmlPropertyData::Flags flags;
91
92     if (p.isConstant())
93         flags |= QQmlPropertyData::IsConstant;
94     if (p.isWritable())
95         flags |= QQmlPropertyData::IsWritable;
96     if (p.isResettable())
97         flags |= QQmlPropertyData::IsResettable;
98     if (p.isFinal())
99         flags |= QQmlPropertyData::IsFinal;
100     if (p.isEnumType())
101         flags |= QQmlPropertyData::IsEnumType;
102
103     return flags;
104 }
105
106 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
107 // load
108 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
109 {
110     Q_ASSERT(propType != -1);
111
112     QQmlPropertyData::Flags flags;
113
114     if (propType == QMetaType::QObjectStar) {
115         flags |= QQmlPropertyData::IsQObjectDerived;
116     } else if (propType == QMetaType::QVariant) {
117         flags |= QQmlPropertyData::IsQVariant;
118     } else if (propType < (int)QVariant::UserType) {
119     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
120         flags |= QQmlPropertyData::IsQmlBinding;
121     } else if (propType == qMetaTypeId<QJSValue>()) {
122         flags |= QQmlPropertyData::IsQJSValue;
123     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
124         flags |= QQmlPropertyData::IsV8Handle;
125     } else {
126         QQmlMetaType::TypeCategory cat =
127             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
128                    : QQmlMetaType::typeCategory(propType);
129
130         if (cat == QQmlMetaType::Object)
131             flags |= QQmlPropertyData::IsQObjectDerived;
132         else if (cat == QQmlMetaType::List)
133             flags |= QQmlPropertyData::IsQList;
134     }
135
136     return flags;
137 }
138
139 static int metaObjectSignalCount(const QMetaObject *metaObject)
140 {
141     int signalCount = 0;
142     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
143         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
144     return signalCount;
145 }
146
147 QQmlPropertyData::Flags
148 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
149 {
150     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
151 }
152
153 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
154 {
155     Q_UNUSED(engine);
156
157     coreIndex = p.propertyIndex();
158     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
159     Q_ASSERT(p.revision() <= Q_INT16_MAX);
160     revision = p.revision();
161
162     flags = fastFlagsForProperty(p);
163
164     int type = p.type();
165     if (type == QMetaType::QObjectStar) {
166         propType = type;
167         flags |= QQmlPropertyData::IsQObjectDerived;
168     } else if (type == QMetaType::QVariant) {
169         propType = type;
170         flags |= QQmlPropertyData::IsQVariant;
171     } else if (type == QVariant::UserType || type == -1) {
172         propTypeName = p.typeName();
173         flags |= QQmlPropertyData::NotFullyResolved;
174     } else {
175         propType = type;
176     }
177 }
178
179 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
180 {
181     propType = p.userType();
182     coreIndex = p.propertyIndex();
183     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
184     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
185     Q_ASSERT(p.revision() <= Q_INT16_MAX);
186     revision = p.revision();
187 }
188
189 void QQmlPropertyData::load(const QMetaMethod &m)
190 {
191     coreIndex = m.methodIndex();
192     arguments = 0;
193     flags |= IsFunction;
194     if (m.methodType() == QMetaMethod::Signal)
195         flags |= IsSignal;
196     propType = m.returnType();
197
198     if (m.parameterCount()) {
199         flags |= HasArguments;
200         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
201             flags |= IsV8Function;
202         }
203     }
204
205     if (m.attributes() & QMetaMethod::Cloned)
206         flags |= IsCloned;
207
208     Q_ASSERT(m.revision() <= Q_INT16_MAX);
209     revision = m.revision();
210 }
211
212 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
213 {
214     coreIndex = m.methodIndex();
215     arguments = 0;
216     flags |= IsFunction;
217     if (m.methodType() == QMetaMethod::Signal)
218         flags |= IsSignal;
219     propType = QMetaType::Void;
220
221     const char *returnType = m.typeName();
222     if (!returnType)
223         returnType = "\0";
224     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
225         propTypeName = returnType;
226         flags |= NotFullyResolved;
227     }
228
229     if (m.parameterCount()) {
230         flags |= HasArguments;
231         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
232             flags |= IsV8Function;
233         }
234     }
235
236     if (m.attributes() & QMetaMethod::Cloned)
237         flags |= IsCloned;
238
239     Q_ASSERT(m.revision() <= Q_INT16_MAX);
240     revision = m.revision();
241 }
242
243 /*!
244 Creates a new empty QQmlPropertyCache.
245 */
246 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
247 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
248   signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
249   _metaObject(0), argumentsCache(0)
250 {
251     Q_ASSERT(engine);
252 }
253
254 /*!
255 Creates a new QQmlPropertyCache of \a metaObject.
256 */
257 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
258 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
259   signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
260   _metaObject(0), argumentsCache(0)
261 {
262     Q_ASSERT(engine);
263     Q_ASSERT(metaObject);
264
265     update(engine, metaObject);
266 }
267
268 QQmlPropertyCache::~QQmlPropertyCache()
269 {
270     clear();
271
272     QQmlPropertyCacheMethodArguments *args = argumentsCache;
273     while (args) {
274         QQmlPropertyCacheMethodArguments *next = args->next;
275         if (args->signalParameterStringForJS) delete args->signalParameterStringForJS;
276         if (args->names) delete args->names;
277         free(args);
278         args = next;
279     }
280
281     // We must clear this prior to releasing the parent incase it is a
282     // linked hash
283     stringCache.clear();
284     if (_parent) _parent->release();
285
286     if (_ownMetaObject) free((void *)_metaObject);
287     _metaObject = 0;
288     _parent = 0;
289     engine = 0;
290 }
291
292 void QQmlPropertyCache::destroy()
293 {
294     Q_ASSERT(engine || constructor.IsEmpty());
295     if (constructor.IsEmpty())
296         delete this;
297     else
298         QQmlEnginePrivate::deleteInEngineThread(engine, this);
299 }
300
301 // This is inherited from QQmlCleanup, so it should only clear the things
302 // that are tied to the specific QQmlEngine.
303 void QQmlPropertyCache::clear()
304 {
305     qPersistentDispose(constructor);
306     engine = 0;
307 }
308
309 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
310 {
311     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
312     cache->_parent = this;
313     cache->_parent->addref();
314     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
315     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
316     cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
317     cache->stringCache.linkAndReserve(stringCache, reserve);
318     cache->allowedRevisionCache = allowedRevisionCache;
319     cache->_metaObject = _metaObject;
320     cache->_defaultPropertyName = _defaultPropertyName;
321
322     // We specifically do *NOT* copy the constructor
323
324     return cache;
325 }
326
327 QQmlPropertyCache *QQmlPropertyCache::copy()
328 {
329     return copy(0);
330 }
331
332 QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
333                                                      int signalCount)
334 {
335     QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
336     rv->propertyIndexCache.reserve(propertyCount);
337     rv->methodIndexCache.reserve(methodCount);
338     rv->signalHandlerIndexCache.reserve(signalCount);
339     rv->_metaObject = 0;
340
341     return rv;
342 }
343
344 /*! \internal
345
346     \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
347     This is different from QMetaMethod::methodIndex().
348 */
349 void QQmlPropertyCache::appendProperty(const QString &name,
350                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
351 {
352     QQmlPropertyData data;
353     data.propType = propType;
354     data.coreIndex = coreIndex;
355     data.notifyIndex = notifyIndex;
356     data.flags = flags;
357
358     QQmlPropertyData *old = findNamedProperty(name);
359     if (old)
360         data.markAsOverrideOf(old);
361
362     int index = propertyIndexCache.count();
363     propertyIndexCache.append(data);
364
365     setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
366 }
367
368 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
369                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
370 {
371     QQmlPropertyData data;
372     data.propType = propType;
373     data.coreIndex = coreIndex;
374     data.notifyIndex = notifyIndex;
375     data.flags = flags;
376
377     QQmlPropertyData *old = findNamedProperty(name);
378     if (old)
379         data.markAsOverrideOf(old);
380
381     int index = propertyIndexCache.count();
382     propertyIndexCache.append(data);
383
384     setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
385 }
386
387 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
388                                      const int *types, const QList<QByteArray> &names)
389 {
390     QQmlPropertyData data;
391     data.propType = QVariant::Invalid;
392     data.coreIndex = coreIndex;
393     data.flags = flags;
394     data.arguments = 0;
395
396     QQmlPropertyData handler = data;
397     handler.flags |= QQmlPropertyData::IsSignalHandler;
398
399     if (types) {
400         int argumentCount = *types;
401         typedef QQmlPropertyCacheMethodArguments A;
402         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
403         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
404         args->argumentsValid = true;
405         args->signalParameterStringForJS = 0;
406         args->signalParameterCountForJS = 0;
407         args->parameterError = false;
408         args->names = new QList<QByteArray>(names);
409         args->next = argumentsCache;
410         argumentsCache = args;
411         data.arguments = args;
412     }
413
414     QQmlPropertyData *old = findNamedProperty(name);
415     if (old)
416         data.markAsOverrideOf(old);
417
418     int methodIndex = methodIndexCache.count();
419     methodIndexCache.append(data);
420
421     int signalHandlerIndex = signalHandlerIndexCache.count();
422     signalHandlerIndexCache.append(handler);
423
424     QString handlerName = QLatin1String("on") + name;
425     handlerName[2] = handlerName[2].toUpper();
426
427     setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
428     setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
429 }
430
431 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
432                                      const int *types, const QList<QByteArray> &names)
433 {
434     QQmlPropertyData data;
435     data.propType = QVariant::Invalid;
436     data.coreIndex = coreIndex;
437     data.flags = flags;
438     data.arguments = 0;
439
440     QQmlPropertyData handler = data;
441     handler.flags |= QQmlPropertyData::IsSignalHandler;
442
443     if (types) {
444         int argumentCount = *types;
445         typedef QQmlPropertyCacheMethodArguments A;
446         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
447         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
448         args->argumentsValid = true;
449         args->signalParameterStringForJS = 0;
450         args->signalParameterCountForJS = 0;
451         args->parameterError = false;
452         args->names = new QList<QByteArray>(names);
453         args->next = argumentsCache;
454         argumentsCache = args;
455         data.arguments = args;
456     }
457
458     QQmlPropertyData *old = findNamedProperty(name);
459     if (old)
460         data.markAsOverrideOf(old);
461
462     int methodIndex = methodIndexCache.count();
463     methodIndexCache.append(data);
464
465     int signalHandlerIndex = signalHandlerIndexCache.count();
466     signalHandlerIndexCache.append(handler);
467
468     QString handlerName = QLatin1String("on") + name.toUtf16();
469     handlerName[2] = handlerName[2].toUpper();
470
471     setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
472     setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
473 }
474
475 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
476                                      const QList<QByteArray> &names)
477 {
478     int argumentCount = names.count();
479
480     QQmlPropertyData data;
481     data.propType = QMetaType::QVariant;
482     data.coreIndex = coreIndex;
483
484     typedef QQmlPropertyCacheMethodArguments A;
485     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
486     args->arguments[0] = argumentCount;
487     for (int ii = 0; ii < argumentCount; ++ii)
488         args->arguments[ii + 1] = QMetaType::QVariant;
489     args->argumentsValid = true;
490     args->signalParameterStringForJS = 0;
491     args->signalParameterCountForJS = 0;
492     args->parameterError = false;
493     args->names = 0;
494     if (argumentCount)
495         args->names = new QList<QByteArray>(names);
496     args->next = argumentsCache;
497     argumentsCache = args;
498     data.arguments = args;
499
500     data.flags = flags;
501
502     QQmlPropertyData *old = findNamedProperty(name);
503     if (old)
504         data.markAsOverrideOf(old);
505
506     int methodIndex = methodIndexCache.count();
507     methodIndexCache.append(data);
508
509     setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
510 }
511
512 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
513                                      const QList<QByteArray> &names)
514 {
515     int argumentCount = names.count();
516
517     QQmlPropertyData data;
518     data.propType = QMetaType::QVariant;
519     data.coreIndex = coreIndex;
520
521     typedef QQmlPropertyCacheMethodArguments A;
522     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
523     args->arguments[0] = argumentCount;
524     for (int ii = 0; ii < argumentCount; ++ii)
525         args->arguments[ii + 1] = QMetaType::QVariant;
526     args->argumentsValid = true;
527     args->signalParameterStringForJS = 0;
528     args->signalParameterCountForJS = 0;
529     args->parameterError = false;
530     args->names = 0;
531     if (argumentCount)
532         args->names = new QList<QByteArray>(names);
533     args->next = argumentsCache;
534     argumentsCache = args;
535     data.arguments = args;
536
537     data.flags = flags;
538
539     QQmlPropertyData *old = findNamedProperty(name);
540     if (old)
541         data.markAsOverrideOf(old);
542
543     int methodIndex = methodIndexCache.count();
544     methodIndexCache.append(data);
545
546     setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
547 }
548
549 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
550 const QMetaObject *QQmlPropertyCache::metaObject() const
551 {
552     return _metaObject;
553 }
554
555 // Returns this property cache's metaObject, creating it if necessary.
556 const QMetaObject *QQmlPropertyCache::createMetaObject()
557 {
558     if (!_metaObject) {
559         _ownMetaObject = true;
560
561         QMetaObjectBuilder builder;
562         toMetaObjectBuilder(builder);
563         builder.setSuperClass(_parent->createMetaObject());
564         _metaObject = builder.toMetaObject();
565     }
566
567     return _metaObject;
568 }
569
570 // Returns the name of the default property for this cache
571 QString QQmlPropertyCache::defaultPropertyName() const
572 {
573     return _defaultPropertyName;
574 }
575
576 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
577 {
578     return property(defaultPropertyName(), 0, 0);
579 }
580
581 QQmlPropertyCache *QQmlPropertyCache::parent() const
582 {
583     return _parent;
584 }
585
586 // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
587 // QML
588 const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
589 {
590     while (_parent && (_metaObject == 0 || _ownMetaObject))
591         return _parent->firstCppMetaObject();
592     return _metaObject;
593 }
594
595 QQmlPropertyCache *
596 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
597                                          QQmlPropertyData::Flag propertyFlags,
598                                          QQmlPropertyData::Flag methodFlags,
599                                          QQmlPropertyData::Flag signalFlags)
600 {
601     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
602 }
603
604 QQmlPropertyCache *
605 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
606                                          int revision,
607                                          QQmlPropertyData::Flag propertyFlags,
608                                          QQmlPropertyData::Flag methodFlags,
609                                          QQmlPropertyData::Flag signalFlags)
610 {
611     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
612
613     // Reserve enough space in the name hash for all the methods (including signals), all the
614     // signal handlers and all the properties.  This assumes no name clashes, but this is the
615     // common case.
616     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
617                                          QMetaObjectPrivate::get(metaObject)->signalCount +
618                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
619
620     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
621
622     return rv;
623 }
624
625 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
626                                        int revision,
627                                        QQmlPropertyData::Flag propertyFlags,
628                                        QQmlPropertyData::Flag methodFlags,
629                                        QQmlPropertyData::Flag signalFlags)
630 {
631     Q_UNUSED(revision);
632     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
633
634     _metaObject = metaObject;
635
636     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
637
638     allowedRevisionCache.append(0);
639
640     int methodCount = metaObject->methodCount();
641     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
642     int signalCount = metaObjectSignalCount(metaObject);
643     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
644
645     QQmlAccessorProperties::Properties accessorProperties;
646
647     if (classInfoCount) {
648         int classInfoOffset = metaObject->classInfoOffset();
649         bool hasFastProperty = false;
650         for (int ii = 0; ii < classInfoCount; ++ii) {
651             int idx = ii + classInfoOffset;
652
653             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
654                 hasFastProperty = true;
655             } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
656                 _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
657             }
658         }
659
660         if (hasFastProperty) {
661             accessorProperties = QQmlAccessorProperties::properties(metaObject);
662             if (accessorProperties.count == 0)
663                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
664                        "installed property accessors", metaObject->className());
665         } else {
666 #ifndef QT_NO_DEBUG
667             accessorProperties = QQmlAccessorProperties::properties(metaObject);
668             if (accessorProperties.count != 0)
669                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
670                        "FastProperty class info", metaObject->className());
671 #endif
672         }
673     }
674
675     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
676     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
677     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
678     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
679
680     int methodOffset = metaObject->methodOffset();
681     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
682
683     // update() should have reserved enough space in the vector that this doesn't cause a realloc
684     // and invalidate the stringCache.
685     methodIndexCache.resize(methodCount - methodIndexCacheStart);
686     signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
687     int signalHandlerIndex = signalOffset;
688     for (int ii = methodOffset; ii < methodCount; ++ii) {
689         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
690             continue;
691         QMetaMethod m = metaObject->method(ii);
692         if (m.access() == QMetaMethod::Private)
693             continue;
694
695         // Extract method name
696         // It's safe to keep the raw name pointer
697         Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
698         const char *rawName = m.name().constData();
699         const char *cptr = rawName;
700         char utf8 = 0;
701         while (*cptr) {
702             utf8 |= *cptr & 0x80;
703             ++cptr;
704         }
705
706         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
707         QQmlPropertyData *sigdata = 0;
708
709         data->lazyLoad(m);
710
711         if (data->isSignal())
712             data->flags |= signalFlags;
713         else
714             data->flags |= methodFlags;
715
716         if (!dynamicMetaObject)
717             data->flags |= QQmlPropertyData::IsDirect;
718
719         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
720         data->metaObjectOffset = allowedRevisionCache.count() - 1;
721
722         if (data->isSignal()) {
723             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
724             *sigdata = *data;
725             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
726         }
727
728         QQmlPropertyData *old = 0;
729
730         if (utf8) {
731             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
732             if (StringCache::mapped_type *it = stringCache.value(methodName))
733                 old = it->second;
734             setNamedProperty(methodName, ii, data, (old != 0));
735
736             if (data->isSignal()) {
737                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
738                 setNamedProperty(on, ii, sigdata, (old != 0));
739                 ++signalHandlerIndex;
740             }
741         } else {
742             QHashedCStringRef methodName(rawName, cptr - rawName);
743             if (StringCache::mapped_type *it = stringCache.value(methodName))
744                 old = it->second;
745             setNamedProperty(methodName, ii, data, (old != 0));
746
747             if (data->isSignal()) {
748                 int length = methodName.length();
749
750                 QVarLengthArray<char, 128> str(length+3);
751                 str[0] = 'o';
752                 str[1] = 'n';
753                 str[2] = toupper(rawName[0]);
754                 if (length > 1)
755                     memcpy(&str[3], &rawName[1], length - 1);
756                 str[length + 2] = '\0';
757
758                 QHashedString on(QString::fromLatin1(str.data()));
759                 setNamedProperty(on, ii, data, (old != 0));
760                 ++signalHandlerIndex;
761             }
762         }
763
764         if (old) {
765             // We only overload methods in the same class, exactly like C++
766             if (old->isFunction() && old->coreIndex >= methodOffset)
767                 data->flags |= QQmlPropertyData::IsOverload;
768
769             data->markAsOverrideOf(old);
770         }
771     }
772
773     int propCount = metaObject->propertyCount();
774     int propOffset = metaObject->propertyOffset();
775
776     // update() should have reserved enough space in the vector that this doesn't cause a realloc
777     // and invalidate the stringCache.
778     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
779     for (int ii = propOffset; ii < propCount; ++ii) {
780         QMetaProperty p = metaObject->property(ii);
781         if (!p.isScriptable())
782             continue;
783
784         const char *str = p.name();
785         char utf8 = 0;
786         const char *cptr = str;
787         while (*cptr != 0) {
788             utf8 |= *cptr & 0x80;
789             ++cptr;
790         }
791
792         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
793
794         data->lazyLoad(p, engine);
795         data->flags |= propertyFlags;
796
797         if (!dynamicMetaObject)
798             data->flags |= QQmlPropertyData::IsDirect;
799
800         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
801         data->metaObjectOffset = allowedRevisionCache.count() - 1;
802
803         QQmlPropertyData *old = 0;
804
805         if (utf8) {
806             QHashedString propName(QString::fromUtf8(str, cptr - str));
807             if (StringCache::mapped_type *it = stringCache.value(propName))
808                 old = it->second;
809             setNamedProperty(propName, ii, data, (old != 0));
810         } else {
811             QHashedCStringRef propName(str, cptr - str);
812             if (StringCache::mapped_type *it = stringCache.value(propName))
813                 old = it->second;
814             setNamedProperty(propName, ii, data, (old != 0));
815         }
816
817         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
818
819         // Fast properties may not be overrides or revisioned
820         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
821
822         if (accessorProperty) {
823             data->flags |= QQmlPropertyData::HasAccessors;
824             data->accessors = accessorProperty->accessors;
825             data->accessorData = accessorProperty->data;
826         } else if (old) {
827             data->markAsOverrideOf(old);
828         }
829     }
830 }
831
832 QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
833 {
834     if (p && p->notFullyResolved())
835         resolve(p);
836
837     return p;
838 }
839
840 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
841 {
842     Q_ASSERT(data->notFullyResolved());
843
844     data->propType = QMetaType::type(data->propTypeName);
845
846     if (!data->isFunction())
847         data->flags |= flagsForPropertyType(data->propType, engine);
848
849     data->flags &= ~QQmlPropertyData::NotFullyResolved;
850 }
851
852 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
853 {
854     if (!metaObject)
855         return;
856
857     updateRecur(engine, metaObject->superClass());
858
859     append(engine, metaObject, -1);
860 }
861
862 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
863 {
864     Q_ASSERT(engine);
865     Q_ASSERT(metaObject);
866     Q_ASSERT(stringCache.isEmpty());
867
868     // Preallocate enough space in the index caches for all the properties/methods/signals that
869     // are not cached in a parent cache so that the caches never need to be reallocated as this
870     // would invalidate pointers stored in the stringCache.
871     int pc = metaObject->propertyCount();
872     int mc = metaObject->methodCount();
873     int sc = metaObjectSignalCount(metaObject);
874     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
875     methodIndexCache.reserve(mc - methodIndexCacheStart);
876     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
877
878     // Reserve enough space in the stringCache for all properties/methods/signals including those
879     // cached in a parent cache.
880     stringCache.reserve(pc + mc + sc);
881
882     updateRecur(engine,metaObject);
883 }
884
885 /*! \internal
886     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
887     This is different from QMetaMethod::methodIndex().
888 */
889 QQmlPropertyData *
890 QQmlPropertyCache::signal(int index) const
891 {
892     if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
893         return 0;
894
895     if (index < signalHandlerIndexCacheStart)
896         return _parent->signal(index);
897
898     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
899     if (rv->notFullyResolved()) resolve(rv);
900     Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
901     return rv;
902 }
903
904 int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
905 {
906     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
907         return index;
908
909     if (index < methodIndexCacheStart)
910         return _parent->methodIndexToSignalIndex(index);
911
912     return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
913 }
914
915 QQmlPropertyData *
916 QQmlPropertyCache::property(int index) const
917 {
918     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
919         return 0;
920
921     if (index < propertyIndexCacheStart)
922         return _parent->property(index);
923
924     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
925     return ensureResolved(rv);
926 }
927
928 QQmlPropertyData *
929 QQmlPropertyCache::method(int index) const
930 {
931     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
932         return 0;
933
934     if (index < methodIndexCacheStart)
935         return _parent->method(index);
936
937     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
938     return ensureResolved(rv);
939 }
940
941 QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
942 {
943     QQmlData *data = (object ? QQmlData::get(object) : 0);
944     const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0);
945     return findProperty(it, vmemo, context);
946 }
947
948 namespace {
949
950 inline bool contextHasNoExtensions(QQmlContextData *context)
951 {
952     // This context has no extension if its parent is the engine's rootContext,
953     // which has children but no imports
954     return (!context->parent || !context->parent->imports);
955 }
956
957 inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
958 {
959     return (prop->isFunction() ? vmemo->methodCount()
960                                : prop->isSignalHandler() ? vmemo->signalCount()
961                                                          : vmemo->propertyCount());
962 }
963
964 }
965
966 QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
967 {
968     StringCache::ConstIterator end = stringCache.end();
969
970     if (it != end) {
971         if (vmemo && context && !contextHasNoExtensions(context)) {
972             // Find the highest property offset known to the supplied context
973             do {
974                 if (vmemo->ctxt == context)
975                     break;
976
977                 vmemo = vmemo->parentVMEMetaObject();
978             } while (vmemo);
979         }
980
981         do {
982             // Is this property available to this context?
983             const StringCache::mapped_type &property(it.value());
984             if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo)))
985                 return ensureResolved(property.second);
986
987             it = stringCache.findNext(it);
988         } while (it != end);
989     }
990
991     return 0;
992 }
993
994 QString QQmlPropertyData::name(QObject *object)
995 {
996     if (!object)
997         return QString();
998
999     return name(object->metaObject());
1000 }
1001
1002 QString QQmlPropertyData::name(const QMetaObject *metaObject)
1003 {
1004     if (!metaObject || coreIndex == -1)
1005         return QString();
1006
1007     if (flags & IsFunction) {
1008         QMetaMethod m = metaObject->method(coreIndex);
1009
1010         return QString::fromUtf8(m.name().constData());
1011     } else {
1012         QMetaProperty p = metaObject->property(coreIndex);
1013         return QString::fromUtf8(p.name());
1014     }
1015 }
1016
1017 void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
1018 {
1019     overrideIndexIsProperty = !predecessor->isFunction();
1020     overrideIndex = predecessor->coreIndex;
1021
1022     predecessor->flags |= QQmlPropertyData::IsOverridden;
1023 }
1024
1025 QStringList QQmlPropertyCache::propertyNames() const
1026 {
1027     QStringList keys;
1028     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1029         keys.append(iter.key());
1030     return keys;
1031 }
1032
1033 struct StaticQtMetaObject : public QObject
1034 {
1035     static const QMetaObject *get()
1036         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
1037 };
1038
1039 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
1040 {
1041     QByteArray scope;
1042     QByteArray name;
1043     int scopeIdx = str.lastIndexOf("::");
1044     if (scopeIdx != -1) {
1045         scope = str.left(scopeIdx);
1046         name = str.mid(scopeIdx + 2);
1047     } else {
1048         name = str;
1049     }
1050     const QMetaObject *meta;
1051     if (scope == "Qt")
1052         meta = StaticQtMetaObject::get();
1053     else
1054         meta = metaobj;
1055     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
1056         QMetaEnum m = meta->enumerator(i);
1057         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
1058             return QVariant::Int;
1059     }
1060     return type;
1061 }
1062
1063 /*! \internal
1064     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1065     This is different from QMetaMethod::methodIndex().
1066 */
1067 QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString)
1068 {
1069     QQmlPropertyData *signalData = signal(index);
1070     if (!signalData)
1071         return QString();
1072
1073     typedef QQmlPropertyCacheMethodArguments A;
1074
1075     if (signalData->arguments) {
1076         A *arguments = static_cast<A *>(signalData->arguments);
1077         if (arguments->signalParameterStringForJS) {
1078             if (count)
1079                 *count = arguments->signalParameterCountForJS;
1080             if (arguments->parameterError) {
1081                 if (errorString)
1082                     *errorString = *arguments->signalParameterStringForJS;
1083                 return QString();
1084             }
1085             return *arguments->signalParameterStringForJS;
1086         }
1087     }
1088
1089     QList<QByteArray> parameterNameList = signalParameterNames(index);
1090
1091     if (!signalData->arguments) {
1092         int argc = parameterNameList.count();
1093         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1094         args->arguments[0] = argc;
1095         args->argumentsValid = false;
1096         args->signalParameterStringForJS = 0;
1097         args->signalParameterCountForJS = 0;
1098         args->parameterError = false;
1099         args->names = new QList<QByteArray>(parameterNameList);
1100         signalData->arguments = args;
1101     }
1102
1103     QQmlRewrite::RewriteSignalHandler rewriter;
1104     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1105     const QString &parameters = rewriter.createParameterString(parameterNameList,
1106                                                                ep->v8engine()->illegalNames());
1107
1108     bool error = rewriter.hasParameterError();
1109     A *arguments = static_cast<A *>(signalData->arguments);
1110     arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters);
1111     arguments->signalParameterCountForJS = rewriter.parameterCountForJS();
1112     if (count)
1113         *count = arguments->signalParameterCountForJS;
1114     if (error) {
1115         arguments->parameterError = true;
1116         if (errorString)
1117             *errorString = *arguments->signalParameterStringForJS;
1118         return QString();
1119     }
1120     return *arguments->signalParameterStringForJS;
1121 }
1122
1123 // Returns an array of the arguments for method \a index.  The first entry in the array
1124 // is the number of arguments.
1125 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
1126                                                      QVarLengthArray<int, 9> &dummy,
1127                                                      QByteArray *unknownTypeError)
1128 {
1129     Q_ASSERT(object && index >= 0);
1130
1131     QQmlData *ddata = QQmlData::get(object, false);
1132
1133     if (ddata && ddata->propertyCache) {
1134         typedef QQmlPropertyCacheMethodArguments A;
1135
1136         QQmlPropertyCache *c = ddata->propertyCache;
1137         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
1138
1139         while (index < c->methodIndexCacheStart)
1140             c = c->_parent;
1141
1142         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
1143
1144         if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid)
1145             return static_cast<A *>(rv->arguments)->arguments;
1146
1147         const QMetaObject *metaObject = c->createMetaObject();
1148         Q_ASSERT(metaObject);
1149         QMetaMethod m = metaObject->method(index);
1150
1151         int argc = m.parameterCount();
1152         if (!rv->arguments) {
1153             A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1154             args->arguments[0] = argc;
1155             args->argumentsValid = false;
1156             args->signalParameterStringForJS = 0;
1157             args->signalParameterCountForJS = 0;
1158             args->parameterError = false;
1159             args->names = 0;
1160             rv->arguments = args;
1161         }
1162         A *args = static_cast<A *>(rv->arguments);
1163
1164         QList<QByteArray> argTypeNames; // Only loaded if needed
1165
1166         for (int ii = 0; ii < argc; ++ii) {
1167             int type = m.parameterType(ii);
1168             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1169             if (flags & QMetaType::IsEnumeration)
1170                 type = QVariant::Int;
1171             else if (type == QMetaType::UnknownType ||
1172                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1173                       type != qMetaTypeId<QJSValue>())) {
1174                 //the UserType clause is to catch registered QFlags
1175                 if (argTypeNames.isEmpty())
1176                     argTypeNames = m.parameterTypes();
1177                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1178             }
1179             if (type == QMetaType::UnknownType) {
1180                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1181                 return 0;
1182             }
1183             args->arguments[ii + 1] = type;
1184         }
1185         args->argumentsValid = true;
1186
1187         args->next = c->argumentsCache;
1188         c->argumentsCache = args;
1189         return static_cast<A *>(rv->arguments)->arguments;
1190
1191     } else {
1192         QMetaMethod m = object->metaObject()->method(index);
1193         int argc = m.parameterCount();
1194         dummy.resize(argc + 1);
1195         dummy[0] = argc;
1196         QList<QByteArray> argTypeNames; // Only loaded if needed
1197
1198         for (int ii = 0; ii < argc; ++ii) {
1199             int type = m.parameterType(ii);
1200             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1201             if (flags & QMetaType::IsEnumeration)
1202                 type = QVariant::Int;
1203             else if (type == QMetaType::UnknownType ||
1204                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1205                       type != qMetaTypeId<QJSValue>())) {
1206                 //the UserType clause is to catch registered QFlags)
1207                 if (argTypeNames.isEmpty())
1208                     argTypeNames = m.parameterTypes();
1209                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1210             }
1211             if (type == QMetaType::UnknownType) {
1212                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1213                 return 0;
1214             }
1215             dummy[ii + 1] = type;
1216         }
1217
1218         return dummy.data();
1219     }
1220 }
1221
1222 // Returns the return type of the method.
1223 int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
1224                                         QByteArray *unknownTypeError)
1225 {
1226     Q_ASSERT(object && data.coreIndex >= 0);
1227
1228     int type = data.propType;
1229
1230     const char *propTypeName = 0;
1231
1232     if (type == QMetaType::UnknownType) {
1233         // Find the return type name from the method info
1234         QMetaMethod m;
1235
1236         QQmlData *ddata = QQmlData::get(object, false);
1237         if (ddata && ddata->propertyCache) {
1238             QQmlPropertyCache *c = ddata->propertyCache;
1239             Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
1240
1241             while (data.coreIndex < c->methodIndexCacheStart)
1242                 c = c->_parent;
1243
1244             const QMetaObject *metaObject = c->createMetaObject();
1245             Q_ASSERT(metaObject);
1246             m = metaObject->method(data.coreIndex);
1247         } else {
1248             m = object->metaObject()->method(data.coreIndex);
1249         }
1250
1251         type = m.returnType();
1252         propTypeName = m.typeName();
1253     }
1254
1255     QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1256     if (flags & QMetaType::IsEnumeration) {
1257         type = QVariant::Int;
1258     } else if (type == QMetaType::UnknownType ||
1259                (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1260                type != qMetaTypeId<QJSValue>())) {
1261         //the UserType clause is to catch registered QFlags
1262         type = EnumType(object->metaObject(), propTypeName, type);
1263     }
1264
1265     if (type == QMetaType::UnknownType) {
1266         if (unknownTypeError) *unknownTypeError = propTypeName;
1267     }
1268
1269     return type;
1270 }
1271
1272 int QQmlPropertyCache::originalClone(int index)
1273 {
1274     while (signal(index)->isCloned())
1275         --index;
1276     return index;
1277 }
1278
1279 int QQmlPropertyCache::originalClone(QObject *object, int index)
1280 {
1281     QQmlData *data = QQmlData::get(object, false);
1282     if (data && data->propertyCache) {
1283         QQmlPropertyCache *cache = data->propertyCache;
1284         while (cache->signal(index)->isCloned())
1285             --index;
1286     } else {
1287         while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
1288             --index;
1289     }
1290     return index;
1291 }
1292
1293 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1294 {
1295     Q_ASSERT(metaObject);
1296
1297     QQmlPropertyData rv;
1298     {
1299         const QMetaObject *cmo = metaObject;
1300         const QByteArray propertyName = property.toUtf8();
1301         while (cmo) {
1302             int idx = cmo->indexOfProperty(propertyName);
1303             if (idx != -1) {
1304                 QMetaProperty p = cmo->property(idx);
1305                 if (p.isScriptable()) {
1306                     rv.load(p);
1307                     return rv;
1308                 } else {
1309                     while (cmo && cmo->propertyOffset() >= idx)
1310                         cmo = cmo->superClass();
1311                 }
1312             } else {
1313                 cmo = 0;
1314             }
1315         }
1316     }
1317
1318     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1319     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1320     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1321     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1322
1323     int methodCount = metaObject->methodCount();
1324     for (int ii = methodCount - 1; ii >= 0; --ii) {
1325         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1326             continue;
1327         QMetaMethod m = metaObject->method(ii);
1328         if (m.access() == QMetaMethod::Private)
1329             continue;
1330         QString methodName = QString::fromUtf8(m.name().constData());
1331
1332         if (methodName == property) {
1333             rv.load(m);
1334             return rv;
1335         }
1336     }
1337
1338     return rv;
1339 }
1340
1341 inline const QString &qQmlPropertyCacheToString(const QString &string)
1342 {
1343     return string;
1344 }
1345
1346 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1347 {
1348     return QV8Engine::toStringStatic(string.string());
1349 }
1350
1351 template<typename T>
1352 QQmlPropertyData *
1353 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
1354                           QQmlContextData *context, QQmlPropertyData &local)
1355 {
1356     QQmlPropertyCache *cache = 0;
1357
1358     QQmlData *ddata = QQmlData::get(obj, false);
1359
1360     if (ddata && ddata->propertyCache) {
1361         cache = ddata->propertyCache;
1362     } else if (engine) {
1363         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1364         cache = ep->cache(obj);
1365         if (cache) {
1366             ddata = QQmlData::get(obj, true);
1367             cache->addref();
1368             ddata->propertyCache = cache;
1369         }
1370     }
1371
1372     QQmlPropertyData *rv = 0;
1373
1374     if (cache) {
1375         rv = cache->property(name, obj, context);
1376     } else {
1377         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1378         if (local.isValid())
1379             rv = &local;
1380     }
1381
1382     return rv;
1383 }
1384
1385 QQmlPropertyData *
1386 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
1387                             QQmlContextData *context, QQmlPropertyData &local)
1388 {
1389     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
1390 }
1391
1392 QQmlPropertyData *
1393 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1394                                     const QString &name, QQmlContextData *context, QQmlPropertyData &local)
1395 {
1396     return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
1397 }
1398
1399 static inline const QMetaObjectPrivate *priv(const uint* data)
1400 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1401
1402 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1403 {
1404     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1405 }
1406
1407 const char *QQmlPropertyCache::className() const
1408 {
1409     if (!_ownMetaObject && _metaObject)
1410         return _metaObject->className();
1411     else
1412         return _dynamicClassName.constData();
1413 }
1414
1415 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1416 {
1417     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1418                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1419         return lhs.second->coreIndex < rhs.second->coreIndex;
1420     } };
1421
1422     struct Insert { static void in(QQmlPropertyCache *This,
1423                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1424                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1425                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1426         if (data->isSignalHandler())
1427             return;
1428
1429         if (data->isFunction()) {
1430             if (data->coreIndex < This->methodIndexCacheStart)
1431                 return;
1432
1433             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1434             // Overrides can cause the entry to already exist
1435             if (!methods.contains(entry)) methods.append(entry);
1436
1437             data = This->overrideData(data);
1438             if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1439         } else {
1440             if (data->coreIndex < This->propertyIndexCacheStart)
1441                 return;
1442
1443             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1444             // Overrides can cause the entry to already exist
1445             if (!properties.contains(entry)) properties.append(entry);
1446
1447             data = This->overrideData(data);
1448             if (data) Insert::in(This, properties, methods, iter, data);
1449         }
1450
1451     } };
1452
1453     builder.setClassName(_dynamicClassName);
1454
1455     QList<QPair<QString, QQmlPropertyData *> > properties;
1456     QList<QPair<QString, QQmlPropertyData *> > methods;
1457
1458     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1459         Insert::in(this, properties, methods, iter, iter.value().second);
1460
1461     Q_ASSERT(properties.count() == propertyIndexCache.count());
1462     Q_ASSERT(methods.count() == methodIndexCache.count());
1463
1464     qSort(properties.begin(), properties.end(), Sort::lt);
1465     qSort(methods.begin(), methods.end(), Sort::lt);
1466
1467     for (int ii = 0; ii < properties.count(); ++ii) {
1468         QQmlPropertyData *data = properties.at(ii).second;
1469
1470         int notifierId = -1;
1471         if (data->notifyIndex != -1)
1472             notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
1473
1474         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1475                                                             QMetaType::typeName(data->propType),
1476                                                             notifierId);
1477
1478         property.setReadable(true);
1479         property.setWritable(data->isWritable());
1480         property.setResettable(data->isResettable());
1481     }
1482
1483     for (int ii = 0; ii < methods.count(); ++ii) {
1484         QQmlPropertyData *data = methods.at(ii).second;
1485
1486         QByteArray returnType;
1487         if (data->propType != 0)
1488             returnType = QMetaType::typeName(data->propType);
1489
1490         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1491
1492         QQmlPropertyCacheMethodArguments *arguments = 0;
1493         if (data->hasArguments()) {
1494             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1495             Q_ASSERT(arguments->argumentsValid);
1496             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1497                 if (ii != 0) signature.append(",");
1498                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1499             }
1500         }
1501
1502         signature.append(")");
1503
1504         QMetaMethodBuilder method;
1505         if (data->isSignal()) {
1506             method = builder.addSignal(signature);
1507         } else {
1508             method = builder.addSlot(signature);
1509         }
1510         method.setAccess(QMetaMethod::Protected);
1511
1512         if (arguments && arguments->names)
1513             method.setParameterNames(*arguments->names);
1514
1515         if (!returnType.isEmpty())
1516             method.setReturnType(returnType);
1517     }
1518
1519     if (!_defaultPropertyName.isEmpty()) {
1520         QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
1521         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1522             Q_ASSERT(!dp->isFunction());
1523             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1524         }
1525     }
1526 }
1527
1528 /*! \internal
1529     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1530     This is different from QMetaMethod::methodIndex().
1531 */
1532 QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
1533 {
1534     QQmlPropertyData *signalData = signal(index);
1535     if (signalData && signalData->hasArguments()) {
1536         QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments;
1537         if (args && args->names)
1538             return *args->names;
1539         const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
1540         return method.parameterNames();
1541     }
1542     return QList<QByteArray>();
1543 }
1544
1545 // Returns true if \a from is assignable to a property of type \a to
1546 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1547 {
1548     Q_ASSERT(!from.isNull() && !to.isNull());
1549
1550     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1551         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1552     } };
1553
1554     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1555     if (tom == &QObject::staticMetaObject) return true;
1556
1557     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1558         QQmlPropertyCache *fromp = from._m.asT1();
1559         QQmlPropertyCache *top = to._m.asT1();
1560
1561         while (fromp) {
1562             if (fromp == top) return true;
1563             fromp = fromp->parent();
1564         }
1565     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1566         QQmlPropertyCache *fromp = from._m.asT1();
1567
1568         while (fromp) {
1569             const QMetaObject *fromm = fromp->metaObject();
1570             if (fromm && I::equal(fromm, tom)) return true;
1571             fromp = fromp->parent();
1572         }
1573     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1574         const QMetaObject *fromm = from._m.asT2();
1575
1576         if (!tom) return false;
1577
1578         while (fromm) {
1579             if (I::equal(fromm, tom)) return true;
1580             fromm = fromm->superClass();
1581         }
1582     } else { // QMetaObject -> QMetaObject
1583         const QMetaObject *fromm = from._m.asT2();
1584
1585         while (fromm) {
1586             if (I::equal(fromm, tom)) return true;
1587             fromm = fromm->superClass();
1588         }
1589     }
1590
1591     return false;
1592 }
1593
1594 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1595 {
1596     if (_m.isNull()) return 0;
1597     if (_m.isT1()) return _m.asT1();
1598     else return e->cache(_m.asT2());
1599 }
1600
1601 QT_END_NAMESPACE