aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-03-23 14:16:43 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-27 05:17:13 +0200
commit965588737321d10fd1fbca3f89b4c6257b7b5d47 (patch)
tree95d069b6ce910c4f8bf8f71d50bebc4fe35a6b1f /src
parent4a161cfa0cf9167b575bdf7ff5685b9bf17c6960 (diff)
Restrict v8 property lookup to the execution context
When resolving property names, only properties known to the current context of execution should be available. If a property name has been overriden by a component extension, code executing in the context of the base component should resolve the property name to the property available inside the base component or its bases. Task-number: QTBUG-24891 Change-Id: I9687cc28e108226d5a939627a901c8254344b598 Reviewed-by: Michael Brasser <michael.brasser@nokia.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp2
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h8
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp47
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h546
-rw-r--r--src/qml/qml/qqmlcompiler.cpp6
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmllist.cpp2
-rw-r--r--src/qml/qml/qqmlproperty.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp240
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h48
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h17
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp2
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp12
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp8
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp57
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h20
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp12
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp7
18 files changed, 562 insertions, 482 deletions
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
index 07929121d5..0a088a8ff6 100644
--- a/src/qml/debugger/qqmlenginedebugservice.cpp
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -719,7 +719,7 @@ bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method,
QQmlPropertyData dummy;
QQmlPropertyData *prop =
- QQmlPropertyCache::property(context->engine(), object, method, dummy);
+ QQmlPropertyCache::property(context->engine(), object, method, contextData, dummy);
if (!prop || !prop->isVMEFunction())
return false;
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
index a4b20d9e2a..6200b05878 100644
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ b/src/qml/qml/ftw/qflagpointer_p.h
@@ -82,6 +82,8 @@ public:
inline T *operator->() const;
inline T *operator*() const;
+ inline T *data() const;
+
private:
quintptr ptr_value;
@@ -225,6 +227,12 @@ T *QFlagPointer<T>::operator*() const
return (T *)(ptr_value & ~FlagsMask);
}
+template<typename T>
+T *QFlagPointer<T>::data() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
template<typename T, typename T2>
QBiPointer<T, T2>::QBiPointer()
: ptr_value(0)
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 2dc717b488..d5098fc9e6 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -173,20 +173,16 @@ static inline int primeForNumBits(int numBits)
return (1 << numBits) + prime_deltas[numBits];
}
-void QStringHashData::rehashToSize(int size, IteratorData first,
- IteratorData (*Iterate)(const IteratorData &),
- QStringHashNode *skip)
+void QStringHashData::rehashToSize(int size)
{
short bits = qMax(MinNumBits, (int)numBits);
while (primeForNumBits(bits) < size) bits++;
if (bits > numBits)
- rehashToBits(bits, first, Iterate, skip);
+ rehashToBits(bits);
}
-void QStringHashData::rehashToBits(short bits, IteratorData first,
- IteratorData (*Iterate)(const IteratorData &),
- QStringHashNode *skip)
+void QStringHashData::rehashToBits(short bits)
{
numBits = qMax(MinNumBits, (int)bits);
@@ -194,27 +190,36 @@ void QStringHashData::rehashToBits(short bits, IteratorData first,
if (nb == numBuckets && buckets)
return;
- numBuckets = nb;
-
#ifdef QSTRINGHASH_LINK_DEBUG
if (linkCount)
qFatal("QStringHash: Illegal attempt to rehash a linked hash.");
#endif
- delete [] buckets;
- buckets = new QStringHashNode *[numBuckets];
- ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets);
+ QStringHashNode **newBuckets = new QStringHashNode *[nb];
+ ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
- IteratorData nodeList = first;
- while (nodeList.n) {
- if (nodeList.n != skip) {
- int bucket = nodeList.n->hash % numBuckets;
- nodeList.n->next = buckets[bucket];
- buckets[bucket] = nodeList.n;
- }
-
- nodeList = Iterate(nodeList);
+ // Preserve the existing order within buckets so that items with the
+ // same key will retain the same find/findNext order
+ for (int i = 0; i < numBuckets; ++i) {
+ QStringHashNode *bucket = buckets[i];
+ if (bucket)
+ rehashNode(newBuckets, nb, bucket);
}
+
+ delete [] buckets;
+ buckets = newBuckets;
+ numBuckets = nb;
+}
+
+void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
+{
+ QStringHashNode *next = node->next.data();
+ if (next)
+ rehashNode(newBuckets, nb, next);
+
+ int bucket = node->hash % nb;
+ node->next = newBuckets[bucket];
+ newBuckets[bucket] = node;
}
// Copy of QString's qMemCompare
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index cdc1577987..28bb96da5b 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -144,6 +144,7 @@ public:
inline quint32 hash() const;
+ inline QChar *data();
inline const QChar &at(int) const;
inline const QChar *constData() const;
bool startsWith(const QString &) const;
@@ -246,36 +247,44 @@ public:
QStringData *strData;
};
+ inline QHashedString key() const
+ {
+ if (isQString())
+ return QHashedString(QString((QChar *)strData->data(), length), hash);
+
+ return QHashedString(QString::fromLatin1(ckey, length), hash);
+ }
+
bool isQString() const { return next.flag(); }
void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
inline char *cStrData() const { return (char *)ckey; }
inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); }
- inline bool equals(v8::Handle<v8::String> string) {
+ inline bool equals(v8::Handle<v8::String> string) const {
return isQString()?string->Equals(utf16Data(), length):
string->Equals(cStrData(), length);
}
- inline bool symbolEquals(const QHashedV8String &string) {
+ inline bool symbolEquals(const QHashedV8String &string) const {
Q_ASSERT(string.symbolId() != 0);
return length == string.length() && hash == string.hash() &&
(string.symbolId() == symbolId || equals(string.string()));
}
- inline bool equals(const QHashedV8String &string) {
+ inline bool equals(const QHashedV8String &string) const {
return length == string.length() && hash == string.hash() &&
equals(string.string());
}
- inline bool equals(const QHashedStringRef &string) {
+ inline bool equals(const QHashedStringRef &string) const {
return length == string.length() &&
hash == string.hash() &&
(isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length):
QHashedString::compare(string.constData(), cStrData(), length));
}
- inline bool equals(const QHashedCStringRef &string) {
+ inline bool equals(const QHashedCStringRef &string) const {
return length == string.length() &&
hash == string.hash() &&
(isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length):
@@ -306,20 +315,61 @@ public:
QStringHashNode *n;
void *p;
};
- void rehashToBits(short, IteratorData, IteratorData (*Iterate)(const IteratorData &),
- QStringHashNode *skip = 0);
- void rehashToSize(int, IteratorData, IteratorData (*Iterate)(const IteratorData &),
- QStringHashNode *skip = 0);
+ void rehashToBits(short);
+ void rehashToSize(int);
+ void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
private:
QStringHashData(const QStringHashData &);
QStringHashData &operator=(const QStringHashData &);
};
+// For a supplied key type, in what form do we need to keep a hashed version?
+template<typename T>
+struct HashedForm {};
+
+template<> struct HashedForm<QString> { typedef QHashedString Type; };
+template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
+template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
+template<> struct HashedForm<QHashedV8String> { typedef const QHashedV8String &Type; };
+template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
+template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
+template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
+
+class QStringHashBase
+{
+public:
+ static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
+ static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
+ static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
+ static HashedForm<QHashedV8String>::Type hashedString(const QHashedV8String &s) { return s; }
+ static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
+
+ static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
+ static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
+
+ static const QString &toQString(const QString &s) { return s; }
+ static const QString &toQString(const QHashedString &s) { return s; }
+ static QString toQString(const QHashedV8String &s) { return s.toString(); }
+ static QString toQString(const QHashedStringRef &s) { return s.toString(); }
+
+ static QString toQString(const QLatin1String &s) { return QString(s); }
+ static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
+
+ static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
+ static inline quint32 hashOf(const QHashedV8String &s) { return s.hash(); }
+
+ template<typename K>
+ static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
+};
+
template<class T>
-class QStringHash
+class QStringHash : public QStringHashBase
{
public:
+ typedef QHashedString key_type;
+ typedef T mapped_type;
+
struct Node : public QStringHashNode {
Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
@@ -347,22 +397,30 @@ public:
ReservedNodePool *nodePool;
const QStringHash<T> *link;
- inline Node *findNode(const QString &) const;
- inline Node *findNode(const QHashedString &) const;
- inline Node *findNode(const QHashedStringRef &) const;
- inline Node *findNode(const QHashedCStringRef &) const;
- inline Node *findNode(const QHashedV8String &) const;
+ template<typename K>
+ inline Node *findNode(const K &) const;
+
inline Node *findSymbolNode(const QHashedV8String &) const;
+
inline Node *createNode(const Node &o);
- inline Node *createNode(const QHashedString &, const T &);
- inline Node *createNode(const QHashedCStringRef &, const T &);
- inline Node *takeNode(const QHashedString &key, const T &value);
- inline Node *takeNode(const QHashedCStringRef &key, const T &value);
+ template<typename K>
+ inline Node *createNode(const K &, const T &);
+
+ inline Node *insertNode(Node *, quint32);
+
+ inline void initializeNode(Node *, const QHashedString &key);
+ inline void initializeNode(Node *, const QHashedCStringRef &key);
+
+ template<typename K>
+ inline Node *takeNode(const K &key, const T &value);
+
inline Node *takeNode(const Node &o);
inline void copy(const QStringHash<T> &);
+ void copyNode(const QStringHashNode *otherNode);
+
inline QStringHashData::IteratorData iterateFirst() const;
static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &);
@@ -393,6 +451,9 @@ public:
inline bool operator==(const ConstIterator &o) const;
inline bool operator!=(const ConstIterator &o) const;
+ template<typename K>
+ inline bool equals(const K &) const;
+
inline QHashedString key() const;
inline const T &value() const;
inline const T &operator*() const;
@@ -402,33 +463,31 @@ public:
QStringHashData::IteratorData d;
};
- inline void insert(const QString &, const T &);
- inline void insert(const QHashedString &, const T &);
- inline void insert(const QHashedStringRef &, const T &);
- inline void insert(const QHashedCStringRef &, const T &);
+ template<typename K>
+ inline void insert(const K &, const T &);
+
inline void insert(const ConstIterator &);
- inline T *value(const QString &) const;
- inline T *value(const QHashedString &) const;
- inline T *value(const QHashedStringRef &) const;
- inline T *value(const QHashedV8String &) const;
- inline T *value(const QHashedCStringRef &) const;
+ template<typename K>
+ inline T *value(const K &) const;
+
+ inline T *value(const QHashedV8String &string) const;
inline T *value(const ConstIterator &) const;
- inline bool contains(const QString &) const;
- inline bool contains(const QHashedString &) const;
- inline bool contains(const QHashedStringRef &) const;
- inline bool contains(const QHashedCStringRef &) const;
- inline bool contains(const ConstIterator &) const;
+ template<typename K>
+ inline bool contains(const K &) const;
- inline T &operator[](const QString &);
- inline T &operator[](const QHashedString &);
- inline T &operator[](const QHashedStringRef &);
- inline T &operator[](const QHashedCStringRef &);
+ template<typename K>
+ inline T &operator[](const K &);
inline ConstIterator begin() const;
inline ConstIterator end() const;
+ inline ConstIterator iterator(Node *n) const;
+
+ template<typename K>
+ inline ConstIterator find(const K &) const;
+
inline void reserve(int);
};
@@ -480,7 +539,7 @@ void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalR
if (other.count()) {
data.size = other.data.size;
- data.rehashToSize(other.count() + additionalReserve, iterateFirst(), iterateNext);
+ data.rehashToSize(other.count() + additionalReserve);
if (data.numBuckets == other.data.numBuckets) {
nodePool = new ReservedNodePool;
@@ -493,11 +552,8 @@ void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalR
const_cast<QStringHash<T>&>(other).data.linkCount++;
#endif
- for (int ii = 0; ii < data.numBuckets; ++ii) {
- data.buckets[ii] = 0;
- Node *n = (Node *)other.data.buckets[ii];
- data.buckets[ii] = n;
- }
+ for (int ii = 0; ii < data.numBuckets; ++ii)
+ data.buckets[ii] = (Node *)other.data.buckets[ii];
link = &other;
return;
@@ -538,7 +594,7 @@ void QStringHash<T>::clear()
delete c;
}
// Delete the pool allocated nodes
- if (nodePool) delete nodePool;
+ if (nodePool) delete nodePool;
delete [] data.buckets;
data.buckets = 0;
@@ -576,37 +632,34 @@ bool QStringHash<T>::isLinked() const
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedString &key, const T &value)
+void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
{
- if (nodePool && nodePool->used != nodePool->count) {
- Node *rv = nodePool->nodes + nodePool->used++;
- rv->length = key.length();
- rv->hash = key.hash();
- rv->strData = const_cast<QHashedString &>(key).data_ptr();
- rv->strData->ref.ref();
- rv->setQString(true);
- rv->value = value;
- return rv;
- } else {
- NewedNode *rv = new NewedNode(key, value);
- rv->nextNewed = newedNodes;
- newedNodes = rv;
- return rv;
- }
+ node->length = key.length();
+ node->hash = key.hash();
+ node->strData = const_cast<QHashedString &>(key).data_ptr();
+ node->strData->ref.ref();
+ node->setQString(true);
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedCStringRef &key, const T &value)
+void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
+{
+ node->length = key.length();
+ node->hash = key.hash();
+ node->ckey = key.constData();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
{
if (nodePool && nodePool->used != nodePool->count) {
Node *rv = nodePool->nodes + nodePool->used++;
- rv->length = key.length();
- rv->hash = key.hash();
- rv->ckey = key.constData();
+ initializeNode(rv, hashedString(key));
rv->value = value;
return rv;
} else {
- NewedNode *rv = new NewedNode(key, value);
+ NewedNode *rv = new NewedNode(hashedString(key), value);
rv->nextNewed = newedNodes;
newedNodes = rv;
return rv;
@@ -639,6 +692,20 @@ typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
}
template<class T>
+void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
+{
+ // Copy the predecessor before the successor
+ QStringHashNode *next = otherNode->next.data();
+ if (next)
+ copyNode(next);
+
+ Node *mynode = takeNode(*(const Node *)otherNode);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+}
+
+template<class T>
void QStringHash<T>::copy(const QStringHash<T> &other)
{
Q_ASSERT(data.size == 0);
@@ -646,28 +713,13 @@ void QStringHash<T>::copy(const QStringHash<T> &other)
data.size = other.data.size;
// Ensure buckets array is created
- data.rehashToBits(data.numBits, iterateFirst(), iterateNext);
-
- if (other.link) {
- for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
- Node *o = iter.node();
- Node *n = o->isQString()?findNode(QHashedStringRef((QChar *)o->strData->data(), o->length, o->hash)):
- findNode(QHashedCStringRef(o->ckey, o->length, o->hash));
- if (!n) {
- Node *mynode = takeNode(*o);
- int bucket = mynode->hash % data.numBuckets;
- mynode->next = data.buckets[bucket];
- data.buckets[bucket] = mynode;
- }
- }
- } else {
- for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
- Node *o = iter.node();
- Node *mynode = takeNode(*o);
- int bucket = mynode->hash % data.numBuckets;
- mynode->next = data.buckets[bucket];
- data.buckets[bucket] = mynode;
- }
+ data.rehashToBits(data.numBits);
+
+ // Preserve the existing order within buckets
+ for (int i = 0; i < other.data.numBuckets; ++i) {
+ QStringHashNode *bucket = other.data.buckets[i];
+ if (bucket)
+ copyNode(bucket);
}
}
@@ -719,79 +771,72 @@ QStringHashData::IteratorData QStringHash<T>::iterateFirst() const
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
+typename QStringHash<T>::ConstIterator QStringHash<T>::iterator(Node *n) const
{
- Node *n = takeNode(o);
+ if (!n)
+ return ConstIterator();
- if (data.size >= data.numBuckets)
- data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
-
- int bucket = n->hash % data.numBuckets;
- n->next = data.buckets[bucket];
- data.buckets[bucket] = n;
+ const QStringHash<T> *container = this;
- data.size++;
+ if (link) {
+ // This node could be in the linked hash
+ if ((n >= nodePool->nodes) && (n < (nodePool->nodes + nodePool->used))) {
+ // The node is in this hash
+ } else if ((n >= link->nodePool->nodes) && (n < (link->nodePool->nodes + link->nodePool->used))) {
+ // The node is in the linked hash
+ container = link;
+ } else {
+ const NewedNode *ln = link->newedNodes;
+ while (ln) {
+ if (ln == n) {
+ // This node is in the linked hash's newed list
+ container = link;
+ break;
+ }
+ ln = ln->nextNewed;
+ }
+ }
+ }
- return n;
+ QStringHashData::IteratorData rv;
+ rv.n = n;
+ rv.p = const_cast<QStringHash<T> *>(container);
+ return ConstIterator(rv);
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
{
- Node *n = takeNode(key, value);
-
- if (data.size >= data.numBuckets)
- data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
-
- int bucket = key.hash() % data.numBuckets;
- n->next = data.buckets[bucket];
- data.buckets[bucket] = n;
-
- data.size++;
-
- return n;
+ Node *n = takeNode(o);
+ return insertNode(n, n->hash);
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedCStringRef &key, const T &value)
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
{
Node *n = takeNode(key, value);
+ return insertNode(n, hashOf(key));
+}
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
+{
if (data.size >= data.numBuckets)
- data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+ data.rehashToBits(data.numBits + 1);
- int bucket = key.hash() % data.numBuckets;
+ int bucket = hash % data.numBuckets;
n->next = data.buckets[bucket];
data.buckets[bucket] = n;
- data.size++;
+ data.size++;
return n;
}
template<class T>
-void QStringHash<T>::insert(const QString &key, const T &value)
-{
- QHashedStringRef ch(key);
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- Node *n = link?0:findNode(key);
- if (n) n->value = value;
- else createNode(QHashedString(key, ch.hash()), value);
-}
-
-template<class T>
-void QStringHash<T>::insert(const QHashedString &key, const T &value)
-{
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- Node *n = link?0:findNode(key);
- if (n) n->value = value;
- else createNode(key, value);
-}
-
-template<class T>
-void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
+template<class K>
+void QStringHash<T>::insert(const K &key, const T &value)
{
// If this is a linked hash, we can't rely on owning the node, so we always
// create a new one.
@@ -801,73 +846,19 @@ void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
}
template<class T>
-void QStringHash<T>::insert(const QHashedCStringRef &key, const T &value)
-{
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- Node *n = link?0:findNode(key);
- if (n) n->value = value;
- else createNode(key, value);
-}
-
-template<class T>
-void QStringHash<T>::insert(const ConstIterator &key)
-{
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- if (key.node()->isQString()) {
- QHashedStringRef str((QChar *)key.node()->strData->data(), key.node()->length,
- key.node()->hash);
-
- Node *n = link?0:findNode(str);
- if (n) n->value = key.node()->value;
- else createNode(*key.node());
- } else {
- QHashedCStringRef str(key.node()->ckey, key.node()->length, key.node()->hash);
-
- Node *n = link?0:findNode(str);
- if (n) n->value = key.node()->value;
- else createNode(str, key.node()->value);
- }
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const QString &string) const
+void QStringHash<T>::insert(const ConstIterator &iter)
{
- return findNode(QHashedStringRef(string));
+ insert(iter.key(), iter.value());
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedString &string) const
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
{
- return findNode(QHashedStringRef(string.constData(), string.length(), string.hash()));
-}
+ QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:0;
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
-{
- QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
- while (node && !node->equals(string))
- node = (*node->next);
-
- return (Node *)node;
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedCStringRef &string) const
-{
- QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
- while (node && !node->equals(string))
- node = (*node->next);
-
- return (Node *)node;
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const
-{
- QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
- while (node && !node->equals(string))
+ typename HashedForm<K>::Type hashedKey(hashedString(key));
+ while (node && !node->equals(hashedKey))
node = (*node->next);
return (Node *)node;
@@ -878,7 +869,7 @@ typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8Str
{
Q_ASSERT(string.symbolId() != 0);
- QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ QStringHashNode *node = data.numBuckets?data.buckets[hashOf(string) % data.numBuckets]:0;
while (node && !node->symbolEquals(string))
node = (*node->next);
@@ -889,28 +880,8 @@ typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8Str
}
template<class T>
-T *QStringHash<T>::value(const QString &key) const
-{
- Node *n = findNode(key);
- return n?&n->value:0;
-}
-
-template<class T>
-T *QStringHash<T>::value(const QHashedString &key) const
-{
- Node *n = findNode(key);
- return n?&n->value:0;
-}
-
-template<class T>
-T *QStringHash<T>::value(const QHashedStringRef &key) const
-{
- Node *n = findNode(key);
- return n?&n->value:0;
-}
-
-template<class T>
-T *QStringHash<T>::value(const QHashedCStringRef &key) const
+template<class K>
+T *QStringHash<T>::value(const K &key) const
{
Node *n = findNode(key);
return n?&n->value:0;
@@ -920,10 +891,7 @@ template<class T>
T *QStringHash<T>::value(const ConstIterator &iter) const
{
Node *n = iter.node();
- if (n->isQString())
- return value(QHashedStringRef((QChar *)n->strData->data(), n->length, n->hash));
- else
- return value(QHashedCStringRef(n->ckey, n->length, n->hash));
+ return value(n->key());
}
template<class T>
@@ -934,62 +902,15 @@ T *QStringHash<T>::value(const QHashedV8String &string) const
}
template<class T>
-bool QStringHash<T>::contains(const QString &s) const
-{
- return 0 != value(s);
-}
-
-template<class T>
-bool QStringHash<T>::contains(const QHashedString &s) const
-{
- return 0 != value(s);
-}
-
-template<class T>
-bool QStringHash<T>::contains(const QHashedStringRef &s) const
-{
- return 0 != value(s);
-}
-
-template<class T>
-bool QStringHash<T>::contains(const QHashedCStringRef &s) const
-{
- return 0 != value(s);
-}
-
-template<class T>
-bool QStringHash<T>::contains(const ConstIterator &s) const
-{
- return 0 != value(s);
-}
-
-template<class T>
-T &QStringHash<T>::operator[](const QString &key)
+template<class K>
+bool QStringHash<T>::contains(const K &key) const
{
- QHashedStringRef cs(key);
- Node *n = findNode(cs);
- if (n) return n->value;
- else return createNode(QHashedString(key, cs.hash()), T())->value;
+ return 0 != value(key);
}
template<class T>
-T &QStringHash<T>::operator[](const QHashedString &key)
-{
- Node *n = findNode(key);
- if (n) return n->value;
- else return createNode(key, T())->value;
-}
-
-template<class T>
-T &QStringHash<T>::operator[](const QHashedStringRef &key)
-{
- Node *n = findNode(key);
- if (n) return n->value;
- else return createNode(key, T())->value;
-}
-
-template<class T>
-T &QStringHash<T>::operator[](const QHashedCStringRef &key)
+template<class K>
+T &QStringHash<T>::operator[](const K &key)
{
Node *n = findNode(key);
if (n) return n->value;
@@ -1007,7 +928,7 @@ void QStringHash<T>::reserve(int n)
nodePool->used = 0;
nodePool->nodes = new Node[n];
- data.rehashToSize(n, iterateFirst(), iterateNext);
+ data.rehashToSize(n);
}
template<class T>
@@ -1041,14 +962,17 @@ bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const
}
template<class T>
+template<typename K>
+bool QStringHash<T>::ConstIterator::equals(const K &key) const
+{
+ return d.n->equals(key);
+}
+
+template<class T>
QHashedString QStringHash<T>::ConstIterator::key() const
{
Node *n = (Node *)d.n;
- if (n->isQString()) {
- return QHashedString(QString((QChar *)n->strData->data(), n->length), n->hash);
- } else {
- return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash);
- }
+ return n->key();
}
template<class T>
const T &QStringHash<T>::ConstIterator::value() const
@@ -1083,6 +1007,59 @@ typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
return ConstIterator();
}
+template<class T>
+template<class K>
+typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
+{
+ return iterator(findNode(key));
+}
+
+template<class T>
+class QStringMultiHash : public QStringHash<T>
+{
+public:
+ typedef typename QStringHash<T>::ConstIterator ConstIterator;
+
+ template<typename K>
+ inline void insert(const K &, const T &);
+
+ inline void insert(const ConstIterator &);
+
+ inline ConstIterator findNext(const ConstIterator &) const;
+};
+
+template<class T>
+template<class K>
+void QStringMultiHash<T>::insert(const K &key, const T &value)
+{
+ // Always create a new node
+ QStringHash<T>::createNode(key, value);
+}
+
+template<class T>
+void QStringMultiHash<T>::insert(const ConstIterator &iter)
+{
+ // Always create a new node
+ QStringHash<T>::createNode(iter.key(), iter.value());
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringMultiHash<T>::findNext(const ConstIterator &iter) const
+{
+ QStringHashNode *node = iter.node();
+ if (node) {
+ QHashedString key(node->key());
+
+ while ((node = *node->next)) {
+ if (node->equals(key)) {
+ return QStringHash<T>::iterator(static_cast<typename QStringHash<T>::Node *>(node));
+ }
+ }
+ }
+
+ return ConstIterator();
+}
+
inline uint qHash(const QHashedString &string)
{
return uint(string.hash());
@@ -1311,6 +1288,11 @@ bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
QHashedString::compare(m_data, string.m_data, m_length);
}
+QChar *QHashedStringRef::data()
+{
+ return const_cast<QChar *>(m_data);
+}
+
const QChar &QHashedStringRef::at(int index) const
{
Q_ASSERT(index < m_length);
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index ee8b30aab7..c9f66a4ea0 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -2965,7 +2965,7 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
// XXX TODO: find a better way to get signal name from the property data :-/
for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
iter != parentCache->stringCache.end(); ++iter) {
- if (currPSig == iter.value()) {
+ if (currPSig == (*iter).second) {
seenSignals.insert(iter.key());
break;
}
@@ -3922,7 +3922,7 @@ QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name,
QQmlPropertyCache *cache = propertyCacheForObject(object);
- QQmlPropertyData *d = cache->property(name);
+ QQmlPropertyData *d = cache->property(name, 0, 0);
// Find the first property
while (d && d->isFunction())
@@ -3945,7 +3945,7 @@ QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, b
QQmlPropertyCache *cache = propertyCacheForObject(object);
- QQmlPropertyData *d = cache->property(name);
+ QQmlPropertyData *d = cache->property(name, 0, 0);
if (notInRevision) *notInRevision = false;
while (d && !(d->isFunction()))
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 6c83433d03..8445625201 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -385,7 +385,7 @@ QVariant QQmlContext::contextProperty(const QString &name) const
QObject *obj = data->contextObject;
QQmlPropertyData local;
QQmlPropertyData *property =
- QQmlPropertyCache::property(data->engine, obj, name, local);
+ QQmlPropertyCache::property(data->engine, obj, name, data, local);
if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
}
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index 8698ce339e..2e74f3e18e 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -139,7 +139,7 @@ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQml
QQmlPropertyData local;
QQmlPropertyData *data =
- QQmlPropertyCache::property(engine, object, QLatin1String(property), local);
+ QQmlPropertyCache::property(engine, object, QLatin1String(property), 0, local);
if (!data || !data->isQList()) return;
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index a239b458f3..ded891a061 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -284,7 +284,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlPropertyData local;
QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, obj, pathName, local);
+ QQmlPropertyCache::property(engine, obj, pathName, context, local);
if (!property) return; // Not a property
if (property->isFunction())
@@ -340,7 +340,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
if (ddata && ddata->propertyCache) {
// Try method
- QQmlPropertyData *d = ddata->propertyCache->property(signalName);
+ QQmlPropertyData *d = ddata->propertyCache->property(signalName, currentObject, context);
while (d && !d->isFunction())
d = ddata->propertyCache->overrideData(d);
@@ -353,7 +353,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
// Try property
if (signalName.endsWith(QLatin1String("Changed"))) {
QString propName = signalName.mid(0, signalName.length() - 7);
- QQmlPropertyData *d = ddata->propertyCache->property(propName);
+ QQmlPropertyData *d = ddata->propertyCache->property(propName, currentObject, context);
while (d && d->isFunction())
d = ddata->propertyCache->overrideData(d);
@@ -378,7 +378,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
// Property
QQmlPropertyData local;
QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, terminal, local);
+ QQmlPropertyCache::property(engine, currentObject, terminal, context, local);
if (property && !property->isFunction()) {
object = currentObject;
core = *property;
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 3519d46017..9165f890c7 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -41,8 +41,9 @@
#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>
@@ -53,6 +54,7 @@
#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.
@@ -243,7 +245,8 @@ Creates a new empty QQmlPropertyCache.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
}
@@ -253,7 +256,8 @@ Creates a new QQmlPropertyCache of \a metaObject.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
Q_ASSERT(metaObject);
@@ -351,16 +355,14 @@ void QQmlPropertyCache::appendProperty(const QString &name,
data.notifyIndex = notifyIndex;
data.flags = flags;
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int index = propertyIndexCache.count();
propertyIndexCache.append(data);
- stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
}
void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
@@ -372,15 +374,14 @@ void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
data.notifyIndex = notifyIndex;
data.flags = flags;
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int index = propertyIndexCache.count();
propertyIndexCache.append(data);
- stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
}
void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
@@ -410,21 +411,21 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor
data.arguments = args;
}
- QString handlerName = QLatin1String("on") + name;
- handlerName[2] = handlerName[2].toUpper();
-
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
signalHandlerIndexCache.append(handler);
- stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
- stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+ 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,
@@ -454,20 +455,21 @@ void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flag
data.arguments = args;
}
- QString handlerName = QLatin1String("on") + name.toUtf16();
- handlerName[2] = handlerName[2].toUpper();
-
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
signalHandlerIndexCache.append(handler);
- stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
- stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+ 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,
@@ -497,16 +499,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
data.flags = flags;
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
- stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
@@ -536,15 +536,14 @@ void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flag
data.flags = flags;
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
- stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
+ 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.
@@ -576,7 +575,7 @@ QString QQmlPropertyCache::defaultPropertyName() const
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
- return property(defaultPropertyName());
+ return property(defaultPropertyName(), 0, 0);
}
QQmlPropertyCache *QQmlPropertyCache::parent() const
@@ -730,20 +729,20 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
if (utf8) {
QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ 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(rawName, cptr - rawName);
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ if (StringCache::mapped_type *it = stringCache.value(methodName))
+ old = it->second;
+ setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
int length = methodName.length();
@@ -757,7 +756,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
str[length + 2] = '\0';
QHashedString on(QString::fromLatin1(str.data()));
- stringCache.insert(on, sigdata);
+ setNamedProperty(on, ii, data, (old != 0));
++signalHandlerIndex;
}
}
@@ -766,9 +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;
- old->flags |= QQmlPropertyData::IsOverridden;
+
+ data->markAsOverrideOf(old);
}
}
@@ -806,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);
@@ -826,13 +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;
- old->flags |= QQmlPropertyData::IsOverridden;
+ 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());
@@ -918,8 +922,7 @@ QQmlPropertyCache::property(int index) const
return _parent->property(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- if (rv->notFullyResolved()) resolve(rv);
- return rv;
+ return ensureResolved(rv);
}
QQmlPropertyData *
@@ -932,32 +935,60 @@ QQmlPropertyCache::method(int index) const
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)
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ return (prop->isFunction() ? vmemo->methodCount()
+ : prop->isSignalHandler() ? vmemo->signalCount()
+ : vmemo->propertyCount());
+}
+
+}
+
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
+{
+ 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)
@@ -983,6 +1014,14 @@ 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;
@@ -1311,7 +1350,8 @@ 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;
@@ -1332,7 +1372,7 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
QQmlPropertyData *rv = 0;
if (cache) {
- rv = cache->property(name);
+ rv = cache->property(name, obj, context);
} else {
local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
if (local.isValid())
@@ -1343,17 +1383,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
}
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)
@@ -1416,7 +1456,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QList<QPair<QString, QQmlPropertyData *> > methods;
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
- Insert::in(this, properties, methods, iter, iter.value());
+ Insert::in(this, properties, methods, iter, iter.value().second);
Q_ASSERT(properties.count() == propertyIndexCache.count());
Q_ASSERT(methods.count() == methodIndexCache.count());
@@ -1477,7 +1517,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
}
if (!_defaultPropertyName.isEmpty()) {
- QQmlPropertyData *dp = property(_defaultPropertyName);
+ QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
if (dp && dp->coreIndex >= propertyIndexCacheStart) {
Q_ASSERT(!dp->isFunction());
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index b14e2f4c1f..e846590a85 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -72,6 +72,7 @@ class QQmlPropertyData;
class QQmlAccessors;
class QMetaObjectBuilder;
class QQmlPropertyCacheMethodArguments;
+class QQmlVMEMetaObject;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
@@ -228,6 +229,8 @@ public:
QString name(QObject *);
QString name(const QMetaObject *);
+ void markAsOverrideOf(QQmlPropertyData *predecessor);
+
private:
friend class QQmlPropertyCache;
void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
@@ -274,10 +277,12 @@ public:
const QMetaObject *createMetaObject();
const QMetaObject *firstCppMetaObject() const;
- inline QQmlPropertyData *property(const QHashedV8String &) const;
- QQmlPropertyData *property(const QHashedStringRef &) const;
- QQmlPropertyData *property(const QHashedCStringRef &) const;
- QQmlPropertyData *property(const QString &) const;
+ template<typename K>
+ QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const
+ {
+ return findProperty(stringCache.find(key), object, context);
+ }
+
QQmlPropertyData *property(int) const;
QQmlPropertyData *method(int) const;
QQmlPropertyData *signal(int) const;
@@ -293,9 +298,9 @@ public:
inline QQmlEngine *qmlEngine() const;
static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
- QQmlPropertyData &);
+ QQmlContextData *, QQmlPropertyData &);
static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
- QQmlPropertyData &);
+ QQmlContextData *, QQmlPropertyData &);
static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
QByteArray *unknownTypeError);
static int methodReturnType(QObject *, const QQmlPropertyData &data,
@@ -341,12 +346,31 @@ private:
v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
typedef QVector<QQmlPropertyData> IndexCache;
- typedef QStringHash<QQmlPropertyData *> StringCache;
+ typedef QStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
typedef QVector<int> AllowedRevisionCache;
+ QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
+ QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const;
+
+ QQmlPropertyData *ensureResolved(QQmlPropertyData*) const;
+
void resolve(QQmlPropertyData *) const;
void updateRecur(QQmlEngine *, const QMetaObject *);
+ template<typename K>
+ QQmlPropertyData *findNamedProperty(const K &key)
+ {
+ StringCache::mapped_type *it = stringCache.value(key);
+ return it ? it->second : 0;
+ }
+
+ template<typename K>
+ void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride)
+ {
+ stringCache.insert(key, qMakePair(index, data));
+ _hasPropertyOverrides |= isOverride;
+ }
+
QQmlEngine *engine;
QQmlPropertyCache *_parent;
@@ -361,7 +385,8 @@ private:
AllowedRevisionCache allowedRevisionCache;
v8::Persistent<v8::Function> constructor;
- bool _ownMetaObject;
+ bool _hasPropertyOverrides : 1;
+ bool _ownMetaObject : 1;
const QMetaObject *_metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
@@ -465,13 +490,6 @@ QQmlEngine *QQmlPropertyCache::qmlEngine() const
return engine;
}
-QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const
-{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
-}
-
int QQmlPropertyCache::propertyCount() const
{
return propertyIndexCacheStart + propertyIndexCache.count();
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 3d70761563..8a3e02c5d8 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -187,6 +187,7 @@ protected:
public:
friend class QQmlVMEMetaObjectEndpoint;
friend class QQmlVMEVariantQObjectPtr;
+ friend class QQmlPropertyCache;
QObject *object;
QQmlGuardedContextData ctxt;
@@ -196,6 +197,7 @@ public:
inline int propOffset() const;
inline int methodOffset() const;
inline int signalOffset() const;
+ inline int signalCount() const;
bool hasAssignedMetaObjectData;
QQmlVMEVariant *data;
@@ -224,6 +226,8 @@ public:
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
+ inline QQmlVMEMetaObject *parentVMEMetaObject() const;
+
void listChanged(int);
class List : public QList<QObject*>
{
@@ -276,6 +280,19 @@ int QQmlVMEMetaObject::signalOffset() const
return cache->signalOffset();
}
+int QQmlVMEMetaObject::signalCount() const
+{
+ return cache->signalCount();
+}
+
+QQmlVMEMetaObject *QQmlVMEMetaObject::parentVMEMetaObject() const
+{
+ if (parent.isT1())
+ return static_cast<QQmlVMEMetaObject *>(parent.asT1());
+
+ return 0;
+}
+
QT_END_NAMESPACE
#endif // QQMLVMEMETAOBJECT_P_H
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index bd67a8d5e4..ddc94d8ce4 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -864,7 +864,7 @@ inline quint32 QV4Bindings::toUint32(double n)
} \
QQmlPropertyData *prop = (data && data->propertyCache) ? data->propertyCache->property((index)) : 0; \
if (prop && prop->isOverridden()) { \
- int resolvedIndex = data->propertyCache->property(prop->name(obj))->coreIndex; \
+ int resolvedIndex = data->propertyCache->property(prop->name(obj), obj, context)->coreIndex; \
if ((int)index < resolvedIndex) { \
*(inv) = true; \
goto programExit; \
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 37d71f1941..45e3a72986 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -466,7 +466,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
QQmlPropertyCache *cache = m_expression->context->synthCache;
if (!cache) cache = m_expression->context->metatype;
- QQmlPropertyData *data = cache->property(name);
+ QQmlPropertyData *data = cache->property(name, 0, 0);
if (data && data->hasRevision()) {
if (qmlVerboseCompiler())
@@ -486,7 +486,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
QQmlPropertyCache *cache = m_expression->component->synthCache;
if (!cache) cache = m_expression->component->metatype;
- QQmlPropertyData *data = cache->property(name);
+ QQmlPropertyData *data = cache->property(name, 0, 0);
if (data && data->hasRevision()) {
if (qmlVerboseCompiler())
@@ -612,7 +612,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
<< (*baseName->id + QLatin1Char('.') + ast->name.toString());
} else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
QQmlPropertyCache *cache = m_engine->cache(attachedMeta);
- QQmlPropertyData *data = cache->property(name);
+ QQmlPropertyData *data = cache->property(name, 0, 0);
if (!data || data->isFunction())
return false; // Don't support methods (or non-existing properties ;)
@@ -647,7 +647,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
} else {
QQmlPropertyCache *cache = baseName->meta.propertyCache(m_engine);
if (!cache) return false;
- QQmlPropertyData *data = cache->property(name);
+ QQmlPropertyData *data = cache->property(name, 0, 0);
if (!data || data->isFunction())
return false; // Don't support methods (or non-existing properties ;)
@@ -666,7 +666,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
QQmlPropertyCache *cache =
idObject->synthCache?idObject->synthCache:idObject->metatype;
- QQmlPropertyData *data = cache->property(name);
+ QQmlPropertyData *data = cache->property(name, 0, 0);
if (!data || data->isFunction())
return false; // Don't support methods (or non-existing properties ;)
@@ -690,7 +690,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
if (!cache)
return false;
- if (QQmlPropertyData *data = cache->property(name)) {
+ if (QQmlPropertyData *data = cache->property(name, 0, 0)) {
if (!baseName->property->isFinal() || !data->isFinal())
_invalidatable = true;
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
index 82ff64fac5..80d4000d31 100644
--- a/src/qml/qml/v8/qv8contextwrapper.cpp
+++ b/src/qml/qml/v8/qv8contextwrapper.cpp
@@ -323,7 +323,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
// Search scope object
if (scopeObject) {
v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring,
- QV8QObjectWrapper::CheckRevision);
+ context, QV8QObjectWrapper::CheckRevision);
if (!result.IsEmpty()) return result;
}
scopeObject = 0;
@@ -332,7 +332,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
// Search context object
if (context->contextObject) {
v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring,
- QV8QObjectWrapper::CheckRevision);
+ context, QV8QObjectWrapper::CheckRevision);
if (!result.IsEmpty()) return result;
}
@@ -396,13 +396,13 @@ v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
// Search scope object
if (scopeObject &&
- qobjectWrapper->setProperty(scopeObject, propertystring, value, QV8QObjectWrapper::CheckRevision))
+ qobjectWrapper->setProperty(scopeObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision))
return value;
scopeObject = 0;
// Search context object
if (context->contextObject &&
- qobjectWrapper->setProperty(context->contextObject, propertystring, value,
+ qobjectWrapper->setProperty(context->contextObject, propertystring, context, value,
QV8QObjectWrapper::CheckRevision))
return value;
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 627e453a77..9cb3410478 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -479,6 +479,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
v8::Handle<v8::Value> *objectHandle,
const QHashedV8String &property,
+ QQmlContextData *context,
QV8QObjectWrapper::RevisionMode revisionMode)
{
// XXX More recent versions of V8 introduced "Callable" objects. It is possible that these
@@ -525,9 +526,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
{
QQmlData *ddata = QQmlData::get(object, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(property);
+ result = ddata->propertyCache->property(property, object, context);
else
- result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
}
if (!result)
@@ -708,7 +709,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
}
}
-bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property,
+bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property, QQmlContextData *context,
v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
{
if (engine->qobjectWrapper()->m_toStringString == property ||
@@ -720,7 +721,7 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH
QQmlPropertyData local;
QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
if (!result)
return false;
@@ -756,16 +757,16 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
QHashedV8String propertystring(property);
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
+
v8::Handle<v8::Value> This = info.This();
v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring,
- QV8QObjectWrapper::IgnoreRevision);
+ context, QV8QObjectWrapper::IgnoreRevision);
if (!result.IsEmpty())
return result;
if (QV8Engine::startsWithUpper(property)) {
// Check for attached properties
- QQmlContextData *context = v8engine->callingContext();
-
if (context && context->imports) {
QQmlTypeNameCache::Result r = context->imports->query(propertystring);
@@ -800,7 +801,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
QHashedV8String propertystring(property);
QV8Engine *v8engine = resource->engine;
- bool result = SetProperty(v8engine, object, propertystring, value, QV8QObjectWrapper::IgnoreRevision);
+ QQmlContextData *context = v8engine->callingContext();
+ bool result = SetProperty(v8engine, object, propertystring, context, value, QV8QObjectWrapper::IgnoreRevision);
if (!result) {
QString error = QLatin1String("Cannot assign to non-existent property \"") +
@@ -822,12 +824,13 @@ v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
QV8Engine *engine = resource->engine;
QObject *object = resource->object;
+ QQmlContextData *context = engine->callingContext();
QHashedV8String propertystring(property);
QQmlPropertyData local;
QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, propertystring, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, propertystring, context, local);
if (!result)
return v8::Handle<v8::Integer>();
@@ -960,35 +963,37 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
if (constructor.IsEmpty()) {
v8::Local<v8::FunctionTemplate> ft;
- QString toString = QLatin1String("toString");
- QString destroy = QLatin1String("destroy");
+ const QHashedString toString(QStringLiteral("toString"));
+ const QHashedString destroy(QStringLiteral("destroy"));
+
+ // As we use hash linking, or with property overrides, it is possible that iterating
+ // over the values can yield duplicates. To combat this, we must unique'ify our properties.
+ const bool checkForDuplicates = stringCache.isLinked() || _hasPropertyOverrides;
- // As we use hash linking, it is possible that iterating over the values can give duplicates.
- // To combat this, we must unique'ify our properties.
StringCache uniqueHash;
- if (stringCache.isLinked())
+ if (checkForDuplicates)
uniqueHash.reserve(stringCache.count());
// XXX TODO: Enables fast property accessors. These more than double the property access
// performance, but the cost of setting up this structure hasn't been measured so
// its not guarenteed that this is a win overall. We need to try and measure the cost.
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
- if (stringCache.isLinked()) {
+ if (iter.equals(toString) || iter.equals(destroy))
+ continue;
+
+ if (checkForDuplicates) {
if (uniqueHash.contains(iter))
continue;
uniqueHash.insert(iter);
}
- QQmlPropertyData *property = *iter;
+ QQmlPropertyData *property = (*iter).second;
if (property->notFullyResolved()) resolve(property);
if (property->isFunction())
continue;
v8::AccessorGetter fastgetter = 0;
- v8::AccessorSetter fastsetter = FastValueSetter;
- if (!property->isWritable())
- fastsetter = FastValueSetterReadOnly;
if (property->isQObject())
fastgetter = FAST_GETTER_FUNCTION(property, QObject*);
@@ -1006,10 +1011,6 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
fastgetter = FAST_GETTER_FUNCTION(property, double);
if (fastgetter) {
- QString name = iter.key();
- if (name == toString || name == destroy)
- continue;
-
if (ft.IsEmpty()) {
ft = v8::FunctionTemplate::New();
ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
@@ -1020,11 +1021,15 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
ft->InstanceTemplate()->SetHasExternalResource(true);
}
+ v8::AccessorSetter fastsetter = FastValueSetter;
+ if (!property->isWritable())
+ fastsetter = FastValueSetterReadOnly;
+
// We wrap the raw QQmlPropertyData pointer here. This is safe as the
// pointer will remain valid at least as long as the lifetime of any QObject's of
// this type and the property accessor checks if the object is 0 (deleted) before
// dereferencing the pointer.
- ft->InstanceTemplate()->SetAccessor(engine->toString(name), fastgetter, fastsetter,
+ ft->InstanceTemplate()->SetAccessor(engine->toString(iter.key()), fastgetter, fastsetter,
v8::External::Wrap(property));
}
}
@@ -1371,13 +1376,13 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second;
- if (signalIndex == -1)
+ if (signalIndex < 0)
V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
if (!signalObject)
V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
- if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
v8::Local<v8::Value> functionValue;
diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h
index de2ec30e44..88d36342cc 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper_p.h
+++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h
@@ -100,8 +100,8 @@ public:
static QObject *toQObject(QV8ObjectResource *);
enum RevisionMode { IgnoreRevision, CheckRevision };
- inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, RevisionMode);
- inline bool setProperty(QObject *, const QHashedV8String &, v8::Handle<v8::Value>, RevisionMode);
+ inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, QQmlContextData *, RevisionMode);
+ inline bool setProperty(QObject *, const QHashedV8String &, QQmlContextData *, v8::Handle<v8::Value>, RevisionMode);
void registerWeakQObjectReference(QV8QObjectResource *resource)
{
@@ -121,8 +121,8 @@ private:
v8::Local<v8::Object> newQObject(QObject *, QQmlData *, QV8Engine *);
bool deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor = false);
static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
- const QHashedV8String &, QV8QObjectWrapper::RevisionMode);
- static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &,
+ const QHashedV8String &, QQmlContextData *, QV8QObjectWrapper::RevisionMode);
+ static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &, QQmlContextData *,
v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
const v8::AccessorInfo &info);
@@ -156,24 +156,24 @@ private:
};
v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &string,
- RevisionMode mode)
+ QQmlContextData *context, RevisionMode mode)
{
QQmlData *dd = QQmlData::get(object, false);
if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string)) {
- return GetProperty(m_engine, object, 0, string, mode);
+ dd->propertyCache->property(string, object, context)) {
+ return GetProperty(m_engine, object, 0, string, context, mode);
} else {
return v8::Handle<v8::Value>();
}
}
bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &string,
- v8::Handle<v8::Value> value, RevisionMode mode)
+ QQmlContextData *context, v8::Handle<v8::Value> value, RevisionMode mode)
{
QQmlData *dd = QQmlData::get(object, false);
if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string)) {
- return SetProperty(m_engine, object, string, value, mode);
+ dd->propertyCache->property(string, object, context)) {
+ return SetProperty(m_engine, object, string, context, value, mode);
} else {
return false;
}
diff --git a/src/qml/qml/v8/qv8typewrapper.cpp b/src/qml/qml/v8/qv8typewrapper.cpp
index 4400d30abf..25695a9fbc 100644
--- a/src/qml/qml/v8/qv8typewrapper.cpp
+++ b/src/qml/qml/v8/qv8typewrapper.cpp
@@ -165,6 +165,8 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
return v8::Undefined();
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
+
QObject *object = resource->object;
QHashedV8String propertystring(property);
@@ -183,7 +185,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
} else if (resource->object) {
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- return v8engine->qobjectWrapper()->getProperty(ao, propertystring,
+ return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
QV8QObjectWrapper::IgnoreRevision);
// Fall through to return empty handle
@@ -241,7 +243,8 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
}
// check for property.
- v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(singletonType->qobjectApi, propertystring, QV8QObjectWrapper::IgnoreRevision);
+ v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(singletonType->qobjectApi, propertystring,
+ context, QV8QObjectWrapper::IgnoreRevision);
return rv;
} else if (!singletonType->scriptApi.isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
@@ -272,6 +275,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
return value;
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
QHashedV8String propertystring(property);
@@ -280,7 +284,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
QObject *object = resource->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- v8engine->qobjectWrapper()->setProperty(ao, propertystring, value,
+ v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value,
QV8QObjectWrapper::IgnoreRevision);
} else if (resource->typeNamespace) {
if (QQmlMetaType::SingletonInstance *singletonType = resource->typeNamespace->singletonType(resource->importNamespace)) {
@@ -295,7 +299,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
}
if (singletonType->qobjectApi) {
- v8engine->qobjectWrapper()->setProperty(singletonType->qobjectApi, propertystring, value,
+ v8engine->qobjectWrapper()->setProperty(singletonType->qobjectApi, propertystring, context, value,
QV8QObjectWrapper::IgnoreRevision);
} else if (!singletonType->scriptApi.isUndefined()) {
QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
index 0408df4b00..33166322ed 100644
--- a/src/qml/qml/v8/qv8valuetypewrapper.cpp
+++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp
@@ -313,10 +313,10 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
{
QQmlData *ddata = QQmlData::get(r->type, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(propertystring);
+ result = ddata->propertyCache->property(propertystring, 0, 0);
else
result = QQmlPropertyCache::property(r->engine->engine(), r->type,
- propertystring, local);
+ propertystring, 0, local);
}
if (!result)
@@ -324,7 +324,8 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
if (result->isFunction()) {
// calling a Q_INVOKABLE function of a value type
- return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, QV8QObjectWrapper::IgnoreRevision);
+ QQmlContextData *context = r->engine->callingContext();
+ return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \