aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-08-16 10:11:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-18 13:03:13 +0200
commitb6a6a6387e279c431d520243345530fa19bd96c5 (patch)
treeb2551748458f0728ba6a5c403c4d56c61caa072f
parent091f20de8c7fc33ae82b12c1ee5a7835da1daa81 (diff)
Optimize setting new properties on objects
When a property on an object is set for the first time, this triggers a change in internal class for the object. Record that change in the lookup, and do the same transition in the future. Change-Id: Ib0e8ac61ce3aaecb736532600740cec51996e3d6 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp51
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h5
-rw-r--r--src/qml/jsruntime/qv4object.cpp46
-rw-r--r--src/qml/jsruntime/qv4object_p.h1
4 files changed, 94 insertions, 9 deletions
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index b5ea877bd4..345611d46c 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -362,4 +362,55 @@ void Lookup::setter0(Lookup *l, const Value &object, const Value &value)
setterGeneric(l, object, value);
}
+void Lookup::setterInsert0(Lookup *l, const Value &object, const Value &value)
+{
+ Object *o = object.asObject();
+ if (o && o->internalClass == l->classList[0]) {
+ if (!o->prototype) {
+ o->memberData[l->index].value = value;
+ o->internalClass = l->classList[3];
+ return;
+ }
+ }
+
+ l->setter = setterGeneric;
+ setterGeneric(l, object, value);
+}
+
+void Lookup::setterInsert1(Lookup *l, const Value &object, const Value &value)
+{
+ Object *o = object.asObject();
+ if (o && o->internalClass == l->classList[0]) {
+ Object *p = o->prototype;
+ if (p && p->internalClass == l->classList[1]) {
+ o->memberData[l->index].value = value;
+ o->internalClass = l->classList[3];
+ return;
+ }
+ }
+
+ l->setter = setterGeneric;
+ setterGeneric(l, object, value);
+}
+
+void Lookup::setterInsert2(Lookup *l, const Value &object, const Value &value)
+{
+ Object *o = object.asObject();
+ if (o && o->internalClass == l->classList[0]) {
+ Object *p = o->prototype;
+ if (p && p->internalClass == l->classList[1]) {
+ p = p->prototype;
+ if (p && p->internalClass == l->classList[2]) {
+ o->ensureMemberIndex(l->index);
+ o->memberData[l->index].value = value;
+ o->internalClass = l->classList[3];
+ return;
+ }
+ }
+ }
+
+ l->setter = setterGeneric;
+ setterGeneric(l, object, value);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index e77552826a..3763182e84 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct Lookup {
- enum { Size = 3 };
+ enum { Size = 4 };
union {
void (*getter)(Lookup *l, Value *result, const Value &object);
void (*globalGetter)(Lookup *l, ExecutionContext *ctx, Value *result);
@@ -82,6 +82,9 @@ struct Lookup {
static void setterGeneric(Lookup *l, const Value &object, const Value &value);
static void setter0(Lookup *l, const Value &object, const Value &value);
+ static void setterInsert0(Lookup *l, const Value &object, const Value &value);
+ static void setterInsert1(Lookup *l, const Value &object, const Value &value);
+ static void setterInsert2(Lookup *l, const Value &object, const Value &value);
Property *lookup(Object *obj, PropertyAttributes *attrs);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 45a0a19e2f..01be2d7091 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -293,14 +293,8 @@ void Object::markObjects(Managed *that)
o->markArrayObjects();
}
-Property *Object::insertMember(String *s, PropertyAttributes attributes)
+void Object::ensureMemberIndex(uint idx)
{
- uint idx;
- internalClass = internalClass->addMember(s, attributes, &idx);
-
- if (attributes.isAccessor())
- hasAccessorProperty = 1;
-
if (idx >= memberDataAlloc) {
memberDataAlloc = qMax((uint)8, 2*memberDataAlloc);
Property *newMemberData = new Property[memberDataAlloc];
@@ -310,6 +304,18 @@ Property *Object::insertMember(String *s, PropertyAttributes attributes)
delete [] memberData;
memberData = newMemberData;
}
+}
+
+Property *Object::insertMember(String *s, PropertyAttributes attributes)
+{
+ uint idx;
+ internalClass = internalClass->addMember(s, attributes, &idx);
+
+ if (attributes.isAccessor())
+ hasAccessorProperty = 1;
+
+ ensureMemberIndex(idx);
+
return memberData + idx;
}
@@ -540,7 +546,8 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
{
Object *o = static_cast<Object *>(m);
- uint idx = o->internalClass->find(l->name);
+ InternalClass *c = o->internalClass;
+ uint idx = c->find(l->name);
if (!o->isArrayObject() || idx != ArrayObject::LengthPropertyIndex) {
if (idx != UINT_MAX && o->internalClass->propertyData[idx].isData() && o->internalClass->propertyData[idx].isWritable()) {
l->classList[0] = o->internalClass;
@@ -557,6 +564,29 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
}
o->put(l->name, value);
+
+ if (o->internalClass == c)
+ return;
+ idx = o->internalClass->find(l->name);
+ if (idx == UINT_MAX)
+ return;
+ l->classList[0] = c;
+ l->classList[3] = o->internalClass;
+ l->index = idx;
+ if (!o->prototype) {
+ l->setter = Lookup::setterInsert0;
+ return;
+ }
+ o = o->prototype;
+ l->classList[1] = o->internalClass;
+ if (!o->prototype) {
+ l->setter = Lookup::setterInsert1;
+ return;
+ }
+ o = o->prototype;
+ l->classList[2] = o->internalClass;
+ if (!o->prototype)
+ l->setter = Lookup::setterInsert2;
}
Property *Object::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index e6b1e04286..ea8911124d 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -328,6 +328,7 @@ public:
return false;
}
+ void ensureMemberIndex(uint idx);
inline Value get(String *name, bool *hasProperty = 0)
{ return vtbl->get(this, name, hasProperty); }