Improve value type read performance
authorAaron Kennedy <aaron.kennedy@nokia.com>
Wed, 30 Nov 2011 17:54:03 +0000 (17:54 +0000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 1 Dec 2011 17:55:39 +0000 (18:55 +0100)
On x86, this gives ~3x improvement in property read time.

Change-Id: I8f75e9bb7450bc56ca42f8258c3a5641bc9c18d3
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
src/declarative/qml/v8/qv8valuetypewrapper.cpp
src/declarative/qml/v8/qv8valuetypewrapper_p.h

index 2c46b77..aca0c85 100644 (file)
@@ -105,8 +105,11 @@ void QV8ValueTypeWrapper::destroy()
 {
     qPersistentDispose(m_toString);
     qPersistentDispose(m_constructor);
+    qPersistentDispose(m_toStringSymbol);
 }
 
+static quint32 toStringHash = -1;
+
 void QV8ValueTypeWrapper::init(QV8Engine *engine)
 {
     m_engine = engine;
@@ -119,6 +122,10 @@ void QV8ValueTypeWrapper::init(QV8Engine *engine)
                                         m_toString, v8::DEFAULT,
                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
     m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+
+    m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
+    m_toStringString = QHashedV8String(m_toStringSymbol);
+    toStringHash = m_toStringString.hash();
 }
 
 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
@@ -231,19 +238,30 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
     QV8ValueTypeResource *r =  v8_resource_cast<QV8ValueTypeResource>(info.This());
     if (!r) return v8::Handle<v8::Value>();
 
-    // XXX This is horribly inefficient.  Sadly people seem to have taken a liking to 
-    // value type properties, so we should probably try and optimize it a little.
-    // We should probably just replace all value properties with dedicated accessors.
+    QHashedV8String propertystring(property);
 
-    QByteArray propName = r->engine->toString(property).toUtf8();
-    if (propName == QByteArray("toString")) {
-        return r->engine->valueTypeWrapper()->m_toString;
+    {
+        // Comparing the hash first actually makes a measurable difference here, at least on x86
+        quint32 hash = propertystring.hash();
+        if (hash == toStringHash &&
+            r->engine->valueTypeWrapper()->m_toStringString == propertystring) {
+            return r->engine->valueTypeWrapper()->m_toString;
+        }
     }
 
-    int index = r->type->metaObject()->indexOfProperty(propName.constData());
-    if (index == -1)
-        return v8::Handle<v8::Value>();
+    QDeclarativePropertyData local;
+    QDeclarativePropertyData *result = 0;
+    {
+        QDeclarativeData *ddata = QDeclarativeData::get(r->type, false);
+        if (ddata && ddata->propertyCache)
+            result = ddata->propertyCache->property(propertystring);
+        else
+            result = QDeclarativePropertyCache::property(r->engine->engine(), r->type,
+                                                         propertystring, local);
+    }
 
+    if (!result)
+        return v8::Handle<v8::Value>();
 
     if (r->objectType == QV8ValueTypeResource::Reference) {
         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
@@ -251,7 +269,6 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
         if (!reference->object)
             return v8::Handle<v8::Value>();
 
-
         r->type->read(reference->object, reference->property);
     } else {
         Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
@@ -261,10 +278,25 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
         r->type->setValue(copy->value);
     }
 
-    QMetaProperty prop = r->type->metaObject()->property(index);
-    QVariant result = prop.read(r->type);
+#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
+    if (result->propType == metatype) { \
+        cpptype v; \
+        void *args[] = { &v, 0 }; \
+        r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
+        return constructor(v); \
+    }
 
-    return r->engine->fromVariant(result);
+    // These four types are the most common used by the value type wrappers
+    VALUE_TYPE_LOAD(QMetaType::QReal, qreal, v8::Number::New);
+    VALUE_TYPE_LOAD(QMetaType::Int, int, v8::Integer::New);
+    VALUE_TYPE_LOAD(QMetaType::QString, QString, r->engine->toString);
+    VALUE_TYPE_LOAD(QMetaType::Bool, bool, v8::Boolean::New);
+
+    QVariant v(result->propType, (void *)0);
+    void *args[] = { v.data(), 0 };
+    r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
+    return r->engine->fromVariant(v);
+#undef VALUE_TYPE_ACCESSOR
 }
 
 v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property, 
index 2582560..ce8944e 100644 (file)
@@ -56,6 +56,7 @@
 #include <QtCore/qglobal.h>
 #include <QtDeclarative/qdeclarativelist.h>
 #include <private/qv8_p.h>
+#include <private/qhashedstring_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -92,6 +93,8 @@ private:
     QV8Engine *m_engine;
     v8::Persistent<v8::Function> m_constructor;
     v8::Persistent<v8::Function> m_toString;
+    v8::Persistent<v8::String> m_toStringSymbol;
+    QHashedV8String m_toStringString;
 };
 
 QT_END_NAMESPACE