aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-04-21 14:08:06 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2016-05-12 14:08:37 +0000
commita7b383ab989e74ef552c2ef9c38377e065f1ab0e (patch)
treea278dba709e1133e805d8d64cf3facb5d716ea89
parent32897258b4b9309cae9562a61fea280acd954aa5 (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.cpp2
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp10
-rw-r--r--src/qml/jsruntime/qv4string.cpp114
-rw-r--r--src/qml/jsruntime/qv4string_p.h4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp4
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