aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4string.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-10-31 13:22:07 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-31 20:16:11 +0100
commit02a8fc62491fbdee1913c2c20c939308e05f8d6f (patch)
tree5aa9117fd27491f74574fd2c0e21ab7da73fb236 /src/qml/jsruntime/qv4string.cpp
parenta02863c6cea9cd9dac5cff5c92f64c05de513675 (diff)
Optimize string additions
QV4::String can now either hold a pointer to a QStringData, or a pair of pointers to a left and right string. This reduces the overhead of an addition to allocating a new GC'ed object. To avoid huge chains of linked strings, we use a depth counter, and flatten the string once the depth reaches 16. Change-Id: If7192b8a9f67f0e36a9a8ea34a156c5222f127f4 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jsruntime/qv4string.cpp')
-rw-r--r--src/qml/jsruntime/qv4string.cpp77
1 files changed, 68 insertions, 9 deletions
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index bd4e2b16b0..01d76c48bd 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -105,7 +105,7 @@ const ManagedVTable String::static_vtbl =
{
call,
construct,
- 0 /*markObjects*/,
+ markObjects,
destroy,
0 /*collectDeletables*/,
hasInstance,
@@ -129,6 +129,15 @@ void String::destroy(Managed *that)
static_cast<String*>(that)->~String();
}
+void String::markObjects(Managed *that)
+{
+ String *s = static_cast<String *>(that);
+ if (s->depth) {
+ s->left->mark();
+ s->right->mark();
+ }
+}
+
ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
{
ExecutionEngine *v4 = m->engine();
@@ -138,7 +147,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
if (name->equals(v4->id_length)) {
if (hasProperty)
*hasProperty = true;
- return Primitive::fromInt32(that->_text.length()).asReturnedValue();
+ return Primitive::fromInt32(that->_text->size).asReturnedValue();
}
PropertyAttributes attrs;
Property *pd = v4->stringClass->prototype->__getPropertyDescriptor__(name, &attrs);
@@ -158,7 +167,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
Scope scope(engine);
ScopedString that(scope, static_cast<String *>(m));
- if (index < that->_text.length()) {
+ if (index < (uint)that->_text->size) {
if (hasProperty)
*hasProperty = true;
return Encode(engine->newString(that->toQString().mid(index, 1)));
@@ -207,7 +216,7 @@ PropertyAttributes String::query(const Managed *m, StringRef name)
PropertyAttributes String::queryIndexed(const Managed *m, uint index)
{
const String *that = static_cast<const String *>(m);
- return (index < that->_text.length()) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
+ return (index < (uint)that->_text->size) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
}
bool String::deleteProperty(Managed *, const StringRef)
@@ -215,7 +224,7 @@ bool String::deleteProperty(Managed *, const StringRef)
return false;
}
-bool String::deleteIndexedProperty(Managed *m, uint index)
+bool String::deleteIndexedProperty(Managed *, uint)
{
return false;
}
@@ -240,13 +249,30 @@ bool String::isEqualTo(Managed *t, Managed *o)
String::String(ExecutionEngine *engine, const QString &text)
- : Managed(engine ? engine->emptyClass : 0), _text(text), identifier(0), stringHash(UINT_MAX)
+ : Managed(engine ? engine->emptyClass : 0), _text(const_cast<QString &>(text).data_ptr())
+ , identifier(0), stringHash(UINT_MAX)
+ , depth(0)
{
+ _text->ref.ref();
vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
}
+String::String(ExecutionEngine *engine, String *l, String *r)
+ : Managed(engine ? engine->emptyClass : 0)
+ , left(l), right(r)
+ , stringHash(UINT_MAX), depth(qMax(l->depth, r->depth) + 1)
+{
+ vtbl = &static_vtbl;
+ type = Type_String;
+ subtype = StringType_Unknown;
+
+ // make sure we don't get excessive depth in our strings
+ if (depth >= 16)
+ simplifyString();
+}
+
uint String::toUInt(bool *ok) const
{
*ok = true;
@@ -281,13 +307,46 @@ bool String::equals(const StringRef other) const
void String::makeIdentifierImpl() const
{
+ if (depth)
+ simplifyString();
+ Q_ASSERT(!depth);
engine()->identifierTable->identifier(this);
}
+void String::simplifyString() const
+{
+ Q_ASSERT(depth);
+
+ int l = length();
+ QString result(l, Qt::Uninitialized);
+ QChar *ch = const_cast<QChar *>(result.constData());
+ recursiveAppend(ch);
+ _text = result.data_ptr();
+ _text->ref.ref();
+ identifier = 0;
+ depth = 0;
+}
+
+QChar *String::recursiveAppend(QChar *ch) const
+{
+ if (depth) {
+ ch = left->recursiveAppend(ch);
+ ch = right->recursiveAppend(ch);
+ } else {
+ memcpy(ch, _text->data(), _text->size*sizeof(QChar));
+ ch += _text->size;
+ }
+ return ch;
+}
+
+
void String::createHashValue() const
{
- const QChar *ch = _text.constData();
- const QChar *end = ch + _text.length();
+ if (depth)
+ simplifyString();
+ Q_ASSERT(!depth);
+ const QChar *ch = reinterpret_cast<const QChar *>(_text->data());
+ const QChar *end = ch + _text->size;
// array indices get their number as hash value
bool ok;
@@ -338,7 +397,7 @@ uint String::createHashValue(const char *ch, int length)
uint h = 0xffffffff;
while (ch < end) {
- if (*ch >= 0x80)
+ if ((uchar)(*ch) >= 0x80)
return UINT_MAX;
h = 31 * h + *ch;
++ch;