Introduce an Identifier class

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>
This commit is contained in:
Lars Knoll 2013-06-26 15:03:11 +02:00 committed by The Qt Project
parent f7d727f62c
commit 1b3e648a83
7 changed files with 86 additions and 56 deletions

View 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);

View 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;

View 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() {

View File

@ -47,8 +47,28 @@
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();

View 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

View 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;

View 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 *);