diff options
author | Erik Verbruggen <erik.verbruggen@theqtcompany.com> | 2016-04-21 14:08:06 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-05-12 14:08:37 +0000 |
commit | a7b383ab989e74ef552c2ef9c38377e065f1ab0e (patch) | |
tree | a278dba709e1133e805d8d64cf3facb5d716ea89 | |
parent | 32897258b4b9309cae9562a61fea280acd954aa5 (diff) |
V4: calculate the hash only once when inserting a string.
Reduces the number of instructions of IdentifierTable::identifier by ~15%.
Change-Id: I5a234fa96a6ee3e7202150ded512d1be0b36560d
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r-- | src/qml/jsruntime/qv4identifier.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4identifiertable.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4string.cpp | 114 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4string_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/ftw/qhashedstring.cpp | 4 |
5 files changed, 49 insertions, 85 deletions
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index c8d66b1254..626648067f 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -131,7 +131,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const return 0; Q_ASSERT(d->entries); - uint hash = String::createHashValue(str.constData(), str.length()); + uint hash = String::createHashValue(str.constData(), str.length(), Q_NULLPTR); uint idx = hash % d->alloc; while (1) { if (!d->entries[idx].identifier) diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 5adb17b4ea..3def6defbf 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -118,7 +118,8 @@ void IdentifierTable::addEntry(Heap::String *str) Heap::String *IdentifierTable::insertString(const QString &s) { - uint hash = String::createHashValue(s.constData(), s.length()); + uint subtype; + uint hash = String::createHashValue(s.constData(), s.length(), &subtype); uint idx = hash % alloc; while (Heap::String *e = entries[idx]) { if (e->stringHash == hash && e->toQString() == s) @@ -128,6 +129,8 @@ Heap::String *IdentifierTable::insertString(const QString &s) } Heap::String *str = engine->newString(s); + str->stringHash = hash; + str->subtype = subtype; addEntry(str); return str; } @@ -178,7 +181,8 @@ Identifier *IdentifierTable::identifier(const QString &s) Identifier *IdentifierTable::identifier(const char *s, int len) { - uint hash = String::createHashValue(s, len); + uint subtype; + uint hash = String::createHashValue(s, len, &subtype); if (hash == UINT_MAX) return identifier(QString::fromUtf8(s, len)); @@ -192,6 +196,8 @@ Identifier *IdentifierTable::identifier(const char *s, int len) } Heap::String *str = engine->newString(QString::fromLatin1(s, len)); + str->stringHash = hash; + str->subtype = subtype; addEntry(str); return str->identifier; } diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index abef885249..1455a06c4a 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -49,9 +49,15 @@ using namespace QV4; -static uint toArrayIndex(const QChar *ch, const QChar *end) +static inline uint toUInt(const QChar *ch) { return ch->unicode(); } +#ifndef V4_BOOTSTRAP +static inline uint toUInt(const char *ch) { return *ch; } +#endif + +template <typename T> +static inline uint toArrayIndex(const T *ch, const T *end) { - uint i = ch->unicode() - '0'; + uint i = toUInt(ch) - '0'; if (i > 9) return UINT_MAX; ++ch; @@ -60,7 +66,7 @@ static uint toArrayIndex(const QChar *ch, const QChar *end) return UINT_MAX; while (ch < end) { - uint x = ch->unicode() - '0'; + uint x = toUInt(ch) - '0'; if (x > 9) return UINT_MAX; uint n = i*10 + x; @@ -75,30 +81,26 @@ static uint toArrayIndex(const QChar *ch, const QChar *end) #ifndef V4_BOOTSTRAP -static uint toArrayIndex(const char *ch, const char *end) +template <typename T> +static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype) { - uint i = *ch - '0'; - if (i > 9) - return UINT_MAX; - ++ch; - // reject "01", "001", ... - if (i == 0 && ch != end) - return UINT_MAX; + // array indices get their number as hash value + uint h = ::toArrayIndex(ch, end); + if (h != UINT_MAX) { + if (subtype) + *subtype = Heap::String::StringType_ArrayIndex; + return h; + } while (ch < end) { - uint x = *ch - '0'; - if (x > 9) - return UINT_MAX; - uint n = i*10 + x; - if (n < i) - // overflow - return UINT_MAX; - i = n; + h = 31 * h + toUInt(ch); ++ch; } - return i; -} + if (subtype) + *subtype = Heap::String::StringType_Regular; + return h; +} DEFINE_MANAGED_VTABLE(String); @@ -198,31 +200,6 @@ void Heap::String::simplifyString() const mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar)); } -void Heap::String::createHashValue() const -{ - if (largestSubLength) - simplifyString(); - Q_ASSERT(!largestSubLength); - const QChar *ch = reinterpret_cast<const QChar *>(text->data()); - const QChar *end = ch + text->size; - - // array indices get their number as hash value - stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) { - subtype = Heap::String::StringType_ArrayIndex; - return; - } - - uint h = 0xffffffff; - while (ch < end) { - h = 31 * h + ch->unicode(); - ++ch; - } - - stringHash = h; - subtype = Heap::String::StringType_Regular; -} - void Heap::String::append(const String *data, QChar *ch) { std::vector<const String *> worklist; @@ -243,45 +220,26 @@ void Heap::String::append(const String *data, QChar *ch) } } +void Heap::String::createHashValue() const +{ + if (largestSubLength) + simplifyString(); + Q_ASSERT(!largestSubLength); + const QChar *ch = reinterpret_cast<const QChar *>(text->data()); + const QChar *end = ch + text->size; + stringHash = calculateHashValue(ch, end, &subtype); +} - - -uint String::createHashValue(const QChar *ch, int length) +uint String::createHashValue(const QChar *ch, int length, uint *subtype) { const QChar *end = ch + length; - - // array indices get their number as hash value - uint stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) - return stringHash; - - uint h = 0xffffffff; - while (ch < end) { - h = 31 * h + ch->unicode(); - ++ch; - } - - return h; + return calculateHashValue(ch, end, subtype); } -uint String::createHashValue(const char *ch, int length) +uint String::createHashValue(const char *ch, int length, uint *subtype) { const char *end = ch + length; - - // array indices get their number as hash value - uint stringHash = ::toArrayIndex(ch, end); - if (stringHash != UINT_MAX) - return stringHash; - - uint h = 0xffffffff; - while (ch < end) { - if ((uchar)(*ch) >= 0x80) - return UINT_MAX; - h = 31 * h + *ch; - ++ch; - } - - return h; + return calculateHashValue(ch, end, subtype); } uint String::getLength(const Managed *m) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 3196f49896..60e2655536 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -183,8 +183,8 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { void makeIdentifierImpl(ExecutionEngine *e) const; - static uint createHashValue(const QChar *ch, int length); - static uint createHashValue(const char *ch, int length); + static uint createHashValue(const QChar *ch, int length, uint *subtype); + static uint createHashValue(const char *ch, int length, uint *subtype); bool startsWithUpper() const { const String::Data *l = d(); diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp index 37c1003748..5c5d2a31ac 100644 --- a/src/qml/qml/ftw/qhashedstring.cpp +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -41,12 +41,12 @@ inline quint32 stringHash(const QChar* data, int length) { - return QV4::String::createHashValue(data, length); + return QV4::String::createHashValue(data, length, Q_NULLPTR); } inline quint32 stringHash(const char *data, int length) { - return QV4::String::createHashValue(data, length); + return QV4::String::createHashValue(data, length, Q_NULLPTR); } void QHashedString::computeHash() const |