Performance improvements
authorAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 14 Jun 2011 06:17:39 +0000 (16:17 +1000)
committerAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 14 Jun 2011 06:17:39 +0000 (16:17 +1000)
There are two main changes here.  First, where possible, we mark
properties as "IsDirect" which means that they exist in a C++
QMetaObject (as opposed to a dynamic meta object), which allows us
to call QObject::qt_metacall() directly, bypassing any dynamic meta
object stuff.

The second change is to use an ascii string comparator in V8 where
possible.  V8 stores ASCII string internally as ASCII strings, and
asking it to compare them to a UTF16 string requires a conversion.

src/declarative/qml/qdeclarativepropertycache.cpp
src/declarative/qml/qdeclarativepropertycache_p.h
src/declarative/qml/v8/qhashedstring_p.h
src/declarative/qml/v8/qv8contextwrapper.cpp
src/declarative/qml/v8/qv8engine_p.h
src/declarative/qml/v8/qv8qobjectwrapper.cpp

index ace7616..6a4cf4f 100644 (file)
@@ -44,6 +44,9 @@
 #include "private/qdeclarativeengine_p.h"
 #include "private/qdeclarativebinding_p.h"
 #include "private/qv8engine_p.h"
+
+#include <private/qmetaobject_p.h>
+
 #include <QtCore/qdebug.h>
 
 Q_DECLARE_METATYPE(QScriptValue)
@@ -252,6 +255,8 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
 
     qPersistentDispose(constructor); // Now invalid
 
+    bool dynamicMetaObject = isDynamicMetaObject(metaObject);
+
     allowedRevisionCache.append(0);
 
     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
@@ -279,6 +284,9 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
         else if (m.methodType() == QMetaMethod::Signal)
             data->flags |= signalFlags;
 
+        if (!dynamicMetaObject)
+            data->flags |= Data::IsDirect;
+
         data->metaObjectOffset = allowedRevisionCache.count() - 1;
 
         if (stringCache.contains(methodName)) {
@@ -312,6 +320,9 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
         data->load(p, engine);
         data->flags |= propertyFlags;
 
+        if (!dynamicMetaObject) 
+            data->flags |= Data::IsDirect;
+
         data->metaObjectOffset = allowedRevisionCache.count() - 1;
 
         if (stringCache.contains(propName)) {
@@ -477,4 +488,12 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
     return rv;
 }
 
+static inline const QMetaObjectPrivate *priv(const uint* data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+
+bool QDeclarativePropertyCache::isDynamicMetaObject(const QMetaObject *mo)
+{
+    return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
+}
+
 QT_END_NAMESPACE
index b97c48b..69e810a 100644 (file)
@@ -83,27 +83,28 @@ public:
                     NoFlags           = 0x00000000,
 
                     // Can apply to all properties, except IsFunction
-                    IsConstant        = 0x00000001,
-                    IsWritable        = 0x00000002,
-                    IsResettable      = 0x00000004,
-                    IsAlias           = 0x00000008,
-                    IsFinal           = 0x00000010,
+                    IsConstant        = 0x00000001, // Has CONST flag
+                    IsWritable        = 0x00000002, // Has WRITE function
+                    IsResettable      = 0x00000004, // Has RESET function
+                    IsAlias           = 0x00000008, // Is a QML alias to another property
+                    IsFinal           = 0x00000010, // Has FINAL flag
+                    IsDirect          = 0x00000020, // Exists on a C++ QMetaObject
 
                     // These are mutualy exclusive
-                    IsFunction        = 0x00000020,
-                    IsQObjectDerived  = 0x00000040,
-                    IsEnumType        = 0x00000080,
-                    IsQList           = 0x00000100,
-                    IsQmlBinding      = 0x00000200,
-                    IsQScriptValue    = 0x00000400,
-                    IsV8Handle        = 0x00000800,
+                    IsFunction        = 0x00000040, // Is an invokable
+                    IsQObjectDerived  = 0x00000080, // Property type is a QObject* derived type
+                    IsEnumType        = 0x00000100, // Property type is an enum
+                    IsQList           = 0x00000200, // Property type is a QML list
+                    IsQmlBinding      = 0x00000400, // Property type is a QDeclarativeBinding*
+                    IsQScriptValue    = 0x00000800, // Property type is a QScriptValue
+                    IsV8Handle        = 0x00001000, // Property type is a QDeclarativeV8Handle
 
                     // Apply only to IsFunctions
-                    IsVMEFunction     = 0x00001000,
-                    HasArguments      = 0x00002000,
-                    IsSignal          = 0x00004000,
-                    IsVMESignal       = 0x00008000,
-                    IsV8Function      = 0x00010000
+                    IsVMEFunction     = 0x00002000, // Function was added by QML
+                    HasArguments      = 0x00004000, // Function takes arguments
+                    IsSignal          = 0x00008000, // Function is a signal
+                    IsVMESignal       = 0x00010000, // Signal was added by QML
+                    IsV8Function      = 0x00020000  // Function takes QDeclarativeV8Function* args
         };
         Q_DECLARE_FLAGS(Flags, Flag)
 
@@ -113,6 +114,7 @@ public:
         bool isResettable() const { return flags & IsResettable; }
         bool isAlias() const { return flags & IsAlias; }
         bool isFinal() const { return flags & IsFinal; }
+        bool isDirect() const { return flags & IsDirect; }
         bool isFunction() const { return flags & IsFunction; }
         bool isQObject() const { return flags & IsQObjectDerived; }
         bool isEnum() const { return flags & IsEnumType; }
@@ -171,6 +173,7 @@ public:
     static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &);
     static Data *property(QDeclarativeEngine *, QObject *, const QHashedV8String &, Data &);
 
+    static bool isDynamicMetaObject(const QMetaObject *);
 protected:
     virtual void clear();
 
index ed00aea..0dd111e 100644 (file)
@@ -137,11 +137,27 @@ class QStringHashNode
 {
 public:
     QStringHashNode(const QHashedString &key)
-    : nlist(0), next(0), key(key) {}
+    : nlist(0), next(0), key(key) {
+        if (isAscii()) ascii = key.toAscii();
+    }
 
     QStringHashNode *nlist;
     QStringHashNode *next;
     QHashedString key;
+    QByteArray ascii;
+
+    inline bool equals(v8::Handle<v8::String> string) {
+        return !ascii.isEmpty() && string->Equals((char*)ascii.constData(), ascii.length()) ||
+               ascii.isEmpty() && string->Equals((uint16_t*)key.constData(), key.length());
+    }
+private:
+    bool isAscii() const {
+        for (int ii = 0; ii < key.length(); ++ii) {
+            if (key.at(ii) > 127)
+                return false;
+        }
+        return true;
+    }
 };
 
 struct QStringHashData
@@ -369,8 +385,7 @@ typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &s
         quint32 hash = string.hash();
         node = data.buckets[hash % data.numBuckets];
         int length = string.length();
-        while (node && (length != node->key.length() || hash != node->key.hash() ||
-                        !string.string()->Equals((uint16_t*)node->key.constData(), length)))
+        while (node && (length != node->key.length() || hash != node->key.hash() || !node->equals(string.string())))
             node = node->next;
     } 
 
index c8f4acf..87ea379 100644 (file)
@@ -221,10 +221,7 @@ QDeclarativeContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
 v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property, 
                                                     const v8::AccessorInfo &info)
 {
-    QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
-
-    if (!resource)
-        return v8::Undefined();
+    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
 
     QV8Engine *engine = resource->engine;
 
@@ -236,10 +233,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> proper
 v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, 
                                                 const v8::AccessorInfo &info)
 {
-    QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
-
-    if (!resource)
-        return v8::Undefined();
+    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
 
     // Its possible we could delay the calculation of the "actual" context (in the case
     // of sub contexts) until it is definately needed.
@@ -357,10 +351,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> proper
                                                     v8::Local<v8::Value>,
                                                     const v8::AccessorInfo &info)
 {
-    QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
-
-    if (!resource)
-        return v8::Handle<v8::Value>();
+    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
 
     QV8Engine *engine = resource->engine;
 
@@ -378,10 +369,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
                                                 v8::Local<v8::Value> value,
                                                 const v8::AccessorInfo &info)
 {
-    QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
-
-    if (!resource)
-        return v8::Undefined();
+    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
 
     // Its possible we could delay the calculation of the "actual" context (in the case
     // of sub contexts) until it is definately needed.
index b29f465..46ba0a4 100644 (file)
@@ -128,11 +128,18 @@ public:
 };
 
 template<class T>
-T *v8_resource_cast(v8::Handle<v8::Object> object) {
+inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
     QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
     return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
 }
 
+template<class T>
+inline T *v8_resource_check(v8::Handle<v8::Object> object) {
+    T *resource = static_cast<T *>(object->GetExternalResource());
+    Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
+    return resource;
+}
+
 // Used to allow a QObject method take and return raw V8 handles without having to expose
 // v8 in the public API.
 // Use like this:
index e6c3b29..8fbb1cf 100644 (file)
@@ -166,9 +166,9 @@ void QV8QObjectWrapper::destroy()
 static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8::AccessorInfo &info) \
 { \
     v8::Handle<v8::Object> This = info.This(); \
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(This); \
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This); \
  \
-    if (!resource || resource->object.isNull()) return v8::Undefined(); \
+    if (resource->object.isNull()) return v8::Undefined(); \
  \
     QObject *object = resource->object; \
  \
@@ -188,6 +188,32 @@ static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8
     QMetaObject::metacall(object, QMetaObject::ReadProperty, index, args); \
  \
     return constructor(value); \
+} \
+static v8::Handle<v8::Value> name ## ValueGetterDirect(v8::Local<v8::String>, const v8::AccessorInfo &info) \
+{ \
+    v8::Handle<v8::Object> This = info.This(); \
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This); \
+ \
+    if (resource->object.isNull()) return v8::Undefined(); \
+ \
+    QObject *object = resource->object; \
+ \
+    uint32_t data = info.Data()->Uint32Value(); \
+    int index = data & 0x7FFF; \
+    int notify = (data & 0x7FFF0000) >> 16; \
+    if (notify == 0x7FFF) notify = -1; \
+ \
+    QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \
+    if (ep && notify /* 0 means constant */ && ep->captureProperties) { \
+        typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
+        ep->capturedProperties << CapturedProperty(object, index, notify); \
+    } \
+ \
+    cpptype value = defaultvalue; \
+    void *args[] = { &value, 0 }; \
+    object->qt_metacall(QMetaObject::ReadProperty, index, args); \
+ \
+    return constructor(value); \
 } 
 
 #define CREATE_FUNCTION \
@@ -199,6 +225,10 @@ static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8
         "});"\
     "})"
 
+
+static quint32 toStringHash = -1;
+static quint32 destroyHash = -1;
+
 void QV8QObjectWrapper::init(QV8Engine *engine)
 {
     m_engine = engine;
@@ -210,6 +240,9 @@ void QV8QObjectWrapper::init(QV8Engine *engine)
     m_toStringString = QHashedV8String(m_toStringSymbol);
     m_destroyString = QHashedV8String(m_destroySymbol);
 
+    toStringHash = m_toStringString.hash();
+    destroyHash = m_destroyString.hash();
+
     {
     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
@@ -293,6 +326,53 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
 
     QVariant var = object->metaObject()->property(property.coreIndex).read(object);
     return engine->fromVariant(var);
+
+#undef PROPERTY_LOAD
+}
+
+static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *object, 
+                                                const QDeclarativePropertyCache::Data &property)
+{
+    Q_ASSERT(!property.isFunction());
+
+#define PROPERTY_LOAD(metatype, cpptype, constructor) \
+    if (property.propType == QMetaType:: metatype) { \
+        cpptype type = cpptype(); \
+        void *args[] = { &type, 0 }; \
+        object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args); \
+        return constructor(type); \
+    }
+
+    if (property.isQObject()) {
+        QObject *rv = 0;
+        void *args[] = { &rv, 0 };
+        QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+        return engine->newQObject(rv);
+    } else if (property.isQList()) {
+        return engine->listWrapper()->newList(object, property.coreIndex, property.propType);
+    } else PROPERTY_LOAD(QReal, qreal, v8::Number::New)
+    else PROPERTY_LOAD(Int || property.isEnum(), int, v8::Integer::New)
+    else PROPERTY_LOAD(Bool, bool, v8::Boolean::New)
+    else PROPERTY_LOAD(QString, QString, engine->toString)
+    else PROPERTY_LOAD(UInt, uint, v8::Integer::NewFromUnsigned)
+    else PROPERTY_LOAD(Float, float, v8::Number::New)
+    else PROPERTY_LOAD(Double, double, v8::Number::New)
+    else if(property.isV8Handle()) {
+        QDeclarativeV8Handle handle;
+        void *args[] = { &handle, 0 };
+        object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args); 
+        return reinterpret_cast<v8::Handle<v8::Value> &>(handle);
+    } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) {
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+        QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
+        if (valueType)
+            return engine->newValueType(object, property.coreIndex, valueType);
+    } 
+
+    QVariant var = object->metaObject()->property(property.coreIndex).read(object);
+    return engine->fromVariant(var);
+
+#undef PROPERTY_LOAD
 }
 
 v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object, 
@@ -324,10 +404,14 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
        }
     };
 
-    if (engine->qobjectWrapper()->m_toStringString == property) {
-        return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
-    } else if (engine->qobjectWrapper()->m_destroyString == property) {
-        return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
+    {
+        // Comparing the hash first actually makes a measurable difference here, at least on x86
+        quint32 hash = property.hash();
+        if (hash == toStringHash && engine->qobjectWrapper()->m_toStringString == property) {
+            return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
+        } else if (hash == destroyHash && engine->qobjectWrapper()->m_destroyString == property) {
+            return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
+        }
     }
 
     QDeclarativePropertyCache::Data local;
@@ -343,8 +427,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
     if (!result)
         return v8::Handle<v8::Value>();
 
-    QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0;
-
     if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
         QDeclarativeData *ddata = QDeclarativeData::get(object);
         if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
@@ -363,6 +445,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
         }
     }
 
+    QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0;
     if (ep && ep->captureProperties && !result->isConstant()) {
         if (result->coreIndex == 0)
             ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
@@ -370,7 +453,11 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
             ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
     }
 
-    return LoadProperty(engine, object, *result);
+    if (result->isDirect())  {
+        return LoadPropertyDirect(engine, object, *result);
+    } else {
+        return LoadProperty(engine, object, *result);
+    }
 }
 
 // Setter for writable properties.  Shared between the interceptor and fast property accessor
@@ -491,16 +578,17 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH
 v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property, 
                                                 const v8::AccessorInfo &info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
-    v8::Handle<v8::Value> This = info.This();
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) return v8::Undefined();
+    if (resource->object.isNull()) 
+        return v8::Undefined();
 
     QObject *object = resource->object;
 
     QHashedV8String propertystring(property);
 
     QV8Engine *v8engine = resource->engine;
+    v8::Handle<v8::Value> This = info.This();
     v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring, 
                                                QV8QObjectWrapper::IgnoreRevision);
     if (!result.IsEmpty())
@@ -528,9 +616,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
                                                 v8::Local<v8::Value> value,
                                                 const v8::AccessorInfo &info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) 
+    if (resource->object.isNull()) 
         return value;
 
     QObject *object = resource->object;
@@ -553,9 +641,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
 v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
                                                  const v8::AccessorInfo &info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) 
+    if (resource->object.isNull()) 
         return v8::Handle<v8::Integer>();
 
     QV8Engine *engine = resource->engine;
@@ -577,9 +665,9 @@ v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
 
 v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) 
+    if (resource->object.isNull()) 
         return v8::Array::New();
 
     QObject *object = resource->object;
@@ -628,9 +716,9 @@ FAST_VALUE_GETTER(Double, double, 0, v8::Number::New);
 static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
                             const v8::AccessorInfo& info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) 
+    if (resource->object.isNull()) 
         return; 
 
     QObject *object = resource->object;
@@ -653,9 +741,9 @@ static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
 static void FastValueSetterReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value>,
                                     const v8::AccessorInfo& info)
 {
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
 
-    if (!resource || resource->object.isNull()) 
+    if (resource->object.isNull()) 
         return; 
 
     QV8Engine *v8engine = resource->engine;
@@ -669,7 +757,7 @@ static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void
 {
     Q_ASSERT(handle->IsObject());
     
-    QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(handle->ToObject());
+    QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(handle->ToObject());
 
     Q_ASSERT(resource);
 
@@ -723,19 +811,19 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
                 fastsetter = FastValueSetterReadOnly;
 
             if (property->isQObject()) 
-                fastgetter = QObjectValueGetter;
+                fastgetter = property->isDirect()?QObjectValueGetterDirect:QObjectValueGetter;
             else if (property->propType == QMetaType::Int || property->isEnum()) 
-                fastgetter = IntValueGetter;
+                fastgetter = property->isDirect()?IntValueGetterDirect:IntValueGetter;
             else if (property->propType == QMetaType::Bool)
-                fastgetter = BoolValueGetter;
+                fastgetter = property->isDirect()?BoolValueGetterDirect:BoolValueGetter;
             else if (property->propType == QMetaType::QString)
-                fastgetter = QStringValueGetter;
+                fastgetter = property->isDirect()?QStringValueGetterDirect:QStringValueGetter;
             else if (property->propType == QMetaType::UInt)
-                fastgetter = UIntValueGetter;
+                fastgetter = property->isDirect()?UIntValueGetterDirect:UIntValueGetter;
             else if (property->propType == QMetaType::Float) 
-                fastgetter = FloatValueGetter;
+                fastgetter = property->isDirect()?FloatValueGetterDirect:FloatValueGetter;
             else if (property->propType == QMetaType::Double) 
-                fastgetter = DoubleValueGetter;
+                fastgetter = property->isDirect()?DoubleValueGetterDirect:DoubleValueGetter;
 
             if (fastgetter) {
                 int notifyIndex = property->notifyIndex;