diff options
-rw-r--r-- | src/declarative/qml/qdeclarativepropertycache.cpp | 19 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativepropertycache_p.h | 37 | ||||
-rw-r--r-- | src/declarative/qml/v8/qhashedstring_p.h | 21 | ||||
-rw-r--r-- | src/declarative/qml/v8/qv8contextwrapper.cpp | 20 | ||||
-rw-r--r-- | src/declarative/qml/v8/qv8engine_p.h | 9 | ||||
-rw-r--r-- | src/declarative/qml/v8/qv8qobjectwrapper.cpp | 148 |
6 files changed, 187 insertions, 67 deletions
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index ace76166ee..6a4cf4f710 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -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 diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index b97c48b777..69e810aa97 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -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(); diff --git a/src/declarative/qml/v8/qhashedstring_p.h b/src/declarative/qml/v8/qhashedstring_p.h index ed00aea132..0dd111e189 100644 --- a/src/declarative/qml/v8/qhashedstring_p.h +++ b/src/declarative/qml/v8/qhashedstring_p.h @@ -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; } diff --git a/src/declarative/qml/v8/qv8contextwrapper.cpp b/src/declarative/qml/v8/qv8contextwrapper.cpp index c8f4acf23f..87ea3795ac 100644 --- a/src/declarative/qml/v8/qv8contextwrapper.cpp +++ b/src/declarative/qml/v8/qv8contextwrapper.cpp @@ -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. diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index b29f465e95..46ba0a4431 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -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: diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp index e6c3b29bc5..8fbb1cf8bf 100644 --- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp +++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp @@ -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; |