Introduce an Identifier class
authorLars Knoll <lars.knoll@digia.com>
Wed, 26 Jun 2013 13:03:11 +0000 (15:03 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 28 Jun 2013 12:56:06 +0000 (14:56 +0200)
Identifier are now (opaque) pointers. They contain the
string and it's hash value making conversion from Identifier
back to it's string value a no-op.

Change-Id: Ied7e845a981514890ff6a686e0e3e3057e6b6fbf
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/qml/v4/qv4engine.cpp
src/qml/qml/v4/qv4engine_p.h
src/qml/qml/v4/qv4identifier_p.h
src/qml/qml/v4/qv4internalclass.cpp
src/qml/qml/v4/qv4internalclass_p.h
src/qml/qml/v4/qv4string.cpp
src/qml/qml/v4/qv4string_p.h

index 608a94c..3d2f79f 100644 (file)
@@ -114,7 +114,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
 
     memoryManager->setExecutionEngine(this);
 
-    identifierCache = new Identifiers(this);
+    identifierCache = new IdentifierHash(this);
 
     emptyClass =  new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
 
index 2109acf..b861994 100644 (file)
@@ -100,7 +100,7 @@ struct URIErrorPrototype;
 struct VariantPrototype;
 struct SequencePrototype;
 struct EvalFunction;
-struct Identifiers;
+struct IdentifierHash;
 struct InternalClass;
 class MultiplyWrappedQObjectMap;
 class RegExp;
@@ -119,7 +119,7 @@ struct Q_QML_EXPORT ExecutionEngine
 
     WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
 
-    Identifiers *identifierCache;
+    IdentifierHash *identifierCache;
 
     QQmlJS::Debugging::Debugger *debugger;
 
index f79ee8f..c4ae825 100644 (file)
@@ -49,14 +49,20 @@ QT_BEGIN_NAMESPACE
 
 namespace QV4 {
 
-struct Identifiers
+struct Identifier
+{
+    QString string;
+    uint hashValue;
+};
+
+
+struct IdentifierHash
 {
     ExecutionEngine *engine;
-    uint currentIndex;
     QHash<QString, String *> identifiers;
 public:
 
-    Identifiers(ExecutionEngine *engine) : engine(engine), currentIndex(0) {}
+    IdentifierHash(ExecutionEngine *engine) : engine(engine) {}
 
     String *insert(const QString &s)
     {
@@ -69,31 +75,30 @@ public:
         if (str->subtype == String::StringType_ArrayIndex)
             return str;
 
-        str->identifier = currentIndex;
-        if (currentIndex <= USHRT_MAX) {
-            identifiers.insert(s, str);
-            ++currentIndex;
-        }
+        str->identifier = new Identifier;
+        str->identifier->string = str->toQString();
+        str->identifier->hashValue = str->hashValue();
+        identifiers.insert(s, str);
+
         return str;
     }
 
-    void toIdentifier(String *s) {
-        if (s->identifier != UINT_MAX)
+    void toIdentifier(String *str) {
+        if (str->identifier)
             return;
-        if (s->subtype == String::StringType_Unknown)
-            s->createHashValue();
-        if (s->subtype == String::StringType_ArrayIndex)
+        if (str->subtype == String::StringType_Unknown)
+            str->createHashValue();
+        if (str->subtype == String::StringType_ArrayIndex)
             return;
-        QHash<QString, String*>::const_iterator it = identifiers.find(s->toQString());
+        QHash<QString, String*>::const_iterator it = identifiers.find(str->toQString());
         if (it != identifiers.constEnd()) {
-            s->identifier = (*it)->identifier;
+            str->identifier = (*it)->identifier;
             return;
         }
-        s->identifier = currentIndex;
-        if (currentIndex <= USHRT_MAX) {
-            identifiers.insert(s->toQString(), s);
-            ++currentIndex;
-        }
+        str->identifier = new Identifier;
+        str->identifier->string = str->toQString();
+        str->identifier->hashValue = str->hashValue();
+        identifiers.insert(str->toQString(), str);
     }
 
     void mark() {
index 785808e..e590399 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
+uint hash(const QV4::Identifier *id, uint = 0)
+{
+    quintptr h = (quintptr)id;
+    if (sizeof(quintptr) == sizeof(uint))
+        return h ^ (h >> 8);
+    else
+        return (uint)(h ^ (h >> 8) ^ (h >> 32));
+}
+
+
+uint QV4::qHash(const QV4::InternalClassTransition &t, uint)
+{
+    return hash(t.id) ^ t.flags;
+}
+
 using namespace QV4;
 
+static bool operator==(const InternalClassTransition &a, const InternalClassTransition &b)
+{
+    return a.id == b.id && a.flags == b.flags;
+}
+
 static const uchar prime_deltas[] = {
     0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
     1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
@@ -66,10 +86,7 @@ PropertyHashData::PropertyHashData(int numBits)
 {
     alloc = primeForNumBits(numBits);
     entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
-    for (uint i = 0; i < alloc; ++i) {
-        entries[i].identifier = UINT_MAX;
-        entries[i].index = UINT_MAX;
-    }
+    memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
 }
 
 void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
@@ -81,10 +98,10 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
         PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
         for (uint i = 0; i < d->alloc; ++i) {
             const Entry &e = d->entries[i];
-            if (e.identifier == UINT_MAX || e.index >= classSize)
+            if (!e.identifier || e.index >= classSize)
                 continue;
-            uint idx = e.identifier % dd->alloc;
-            while (dd->entries[idx].identifier != UINT_MAX) {
+            uint idx = hash(e.identifier) % dd->alloc;
+            while (dd->entries[idx].identifier) {
                 ++idx;
                 idx %= dd->alloc;
             }
@@ -96,8 +113,8 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
         d = dd;
     }
 
-    uint idx = entry.identifier % d->alloc;
-    while (d->entries[idx].identifier != UINT_MAX) {
+    uint idx = hash(entry.identifier) % d->alloc;
+    while (d->entries[idx].identifier) {
         ++idx;
         idx %= d->alloc;
     }
@@ -105,15 +122,15 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
     ++d->size;
 }
 
-uint PropertyHash::lookup(uint identifier) const
+uint PropertyHash::lookup(const Identifier *identifier) const
 {
     assert(d->entries);
 
-    uint idx = identifier % d->alloc;
+    uint idx = hash(identifier) % d->alloc;
     while (1) {
         if (d->entries[idx].identifier == identifier)
             return d->entries[idx].index;
-        if (d->entries[idx].identifier == UINT_MAX)
+        if (!d->entries[idx].identifier)
             return UINT_MAX;
         ++idx;
         idx %= d->alloc;
@@ -147,9 +164,9 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
     if (data == propertyData[idx])
         return this;
 
-    uint tid = string->identifier | (data.flags() << 27);
 
-    QHash<int, InternalClass *>::const_iterator tit = transitions.constFind(tid);
+    Transition t = { string->identifier, data.flags() };
+    QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
     if (tit != transitions.constEnd())
         return tit.value();
 
@@ -169,8 +186,8 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
     if (propertyTable.lookup(string->identifier) < size)
         return changeMember(string, data, index);
 
-    uint id = string->identifier | (data.flags() << 27);
-    QHash<int, InternalClass *>::const_iterator tit = transitions.constFind(id);
+    Transition t = { string->identifier, data.flags() };
+    QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
 
     if (index)
         *index = size;
@@ -190,17 +207,17 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
 
     newClass->propertyData.append(data);
     ++newClass->size;
-    transitions.insert(id, newClass);
+    transitions.insert(t, newClass);
     return newClass;
 }
 
-void InternalClass::removeMember(Object *object, uint id)
+void InternalClass::removeMember(Object *object, Identifier *id)
 {
     int propIdx = propertyTable.lookup(id);
     assert(propIdx < size);
 
-    int toRemove = - (int)id;
-    QHash<int, InternalClass *>::const_iterator tit = transitions.constFind(toRemove);
+    Transition t = { id, -1 };
+    QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
 
     if (tit != transitions.constEnd()) {
         object->internalClass = tit.value();
@@ -215,13 +232,13 @@ void InternalClass::removeMember(Object *object, uint id)
         object->internalClass = object->internalClass->addMember(nameMap.at(i), propertyData.at(i));
     }
 
-    transitions.insert(toRemove, object->internalClass);
+    transitions.insert(t, object->internalClass);
 }
 
 uint InternalClass::find(String *string)
 {
     engine->identifierCache->toIdentifier(string);
-    uint id = string->identifier;
+    const Identifier *id = string->identifier;
 
     uint index = propertyTable.lookup(id);
     if (index < size)
@@ -283,7 +300,7 @@ void InternalClass::destroy()
     if (m_frozen)
         m_frozen->destroy();
 
-    for (QHash<int, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
+    for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
          it != end; ++it)
         it.value()->destroy();
 
index 7543844..9bc95da 100644 (file)
@@ -52,12 +52,13 @@ namespace QV4 {
 struct String;
 struct ExecutionEngine;
 struct Object;
+struct Identifier;
 
 struct PropertyHashData;
 struct PropertyHash
 {
     struct Entry {
-        uint identifier;
+        const Identifier *identifier;
         uint index;
     };
 
@@ -68,7 +69,7 @@ struct PropertyHash
     inline ~PropertyHash();
 
     void addEntry(const Entry &entry, int classSize);
-    uint lookup(uint identifier) const;
+    uint lookup(const Identifier *identifier) const;
 
 private:
     PropertyHash &operator=(const PropertyHash &other);
@@ -105,6 +106,12 @@ inline PropertyHash::~PropertyHash()
         delete d;
 }
 
+struct InternalClassTransition
+{
+    Identifier *id;
+    int flags;
+};
+uint qHash(const QV4::InternalClassTransition &t, uint = 0);
 
 struct InternalClass {
     ExecutionEngine *engine;
@@ -113,7 +120,8 @@ struct InternalClass {
 
     QVector<PropertyAttributes> propertyData;
 
-    QHash<int, InternalClass *> transitions; // id to next class, positive means add, negative delete
+    typedef InternalClassTransition Transition;
+    QHash<Transition, InternalClass *> transitions; // id to next class, positive means add, negative delete
 
     InternalClass *m_sealed;
     InternalClass *m_frozen;
@@ -122,7 +130,7 @@ struct InternalClass {
 
     InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
     InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
-    void removeMember(Object *object, uint id);
+    void removeMember(Object *object, Identifier *id);
     uint find(String *s);
 
     InternalClass *sealed();
@@ -136,7 +144,6 @@ private:
     InternalClass(const InternalClass &other);
 };
 
-
 }
 
 QT_END_NAMESPACE
index 97c5401..966da14 100644 (file)
@@ -183,7 +183,7 @@ bool String::deleteIndexedProperty(Managed *m, uint index)
 }
 
 String::String(ExecutionEngine *engine, const QString &text)
-    : Managed(engine ? engine->emptyClass : 0), _text(text), stringHash(UINT_MAX), identifier(UINT_MAX)
+    : Managed(engine ? engine->emptyClass : 0), _text(text), identifier(0), stringHash(UINT_MAX)
 {
     vtbl = &static_vtbl;
     type = Type_String;
index 81108c6..84f2b23 100644 (file)
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
 namespace QV4 {
 
 struct ExecutionEngine;
+struct Identifier;
 
 struct Q_QML_EXPORT String : public Managed {
     enum StringType {
@@ -58,7 +59,7 @@ struct Q_QML_EXPORT String : public Managed {
         StringType_ArrayIndex
     };
 
-    String() : Managed(0), stringHash(UINT_MAX), identifier(UINT_MAX)
+    String() : Managed(0), identifier(0), stringHash(UINT_MAX)
     { vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; }
     String(ExecutionEngine *engine, const QString &text);
     ~String() { _data = 0; }
@@ -68,7 +69,7 @@ struct Q_QML_EXPORT String : public Managed {
             return true;
         if (hashValue() != other->hashValue())
             return false;
-        if (identifier != UINT_MAX && identifier == other->identifier)
+        if (identifier && identifier == other->identifier)
             return true;
         if (subtype >= StringType_UInt && subtype == other->subtype)
             return true;
@@ -100,7 +101,7 @@ struct Q_QML_EXPORT String : public Managed {
     uint toUInt(bool *ok) const;
 
     void makeIdentifier() {
-        if (identifier != UINT_MAX)
+        if (identifier)
             return;
         makeIdentifierImpl();
     }
@@ -118,8 +119,8 @@ struct Q_QML_EXPORT String : public Managed {
     }
 
     QString _text;
+    mutable Identifier *identifier;
     mutable uint stringHash;
-    mutable uint identifier;
 
 protected:
     static void destroy(Managed *);