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:
parent
f7d727f62c
commit
1b3e648a83
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
|
|
|||
Loading…
Reference in New Issue