diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-05-22 16:51:34 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2013-05-23 15:42:24 +0200 |
commit | 31b700b9ddf38283ca06cf78db4a80d674b74661 (patch) | |
tree | c947874ad9e5284c35cab7f3af73a5d4dcd8d12f /src/qml | |
parent | b71fa87e000c5d72d4b2a7146e450dc41dc69055 (diff) |
Replace QV8QObjectResource with QV4::QObjectWrapper
Use a proper sub-class instead of external object resources, as a first
step towards porting the QObject bindings away from V8.
This also replaces the function template / constructor approach and the
faster getter optimization with a plain virtual get in the V4::Object.
Property lookup in QObject bindings will be subject to future optimizations
that will work very differently once we enable the faster V4 lookup mechanism
in QML.
Change-Id: Ib7c2eead5323c22290c2924de786d9cfcf308c03
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4managed_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4value_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8engine.cpp | 17 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8objectresource_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper.cpp | 569 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper_p.h | 55 | ||||
-rw-r--r-- | src/qml/qml/v8/v8.pri | 2 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel.cpp | 16 |
10 files changed, 278 insertions, 399 deletions
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index b7e0a525b7..80c7ebf66a 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -347,9 +347,6 @@ private: QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); - // Implemented in v8/qv8qobjectwrapper.cpp - v8::Handle<v8::Object> newQObject(QObject *, QV8Engine *); - QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names = QList<QByteArray>()); QQmlPropertyData *signal(int, QQmlPropertyCache **) const; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index d40eeff9a5..b22816f0fe 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1032,9 +1032,9 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value) // automatically released by the engine until no other references to it exist. if (QV4::VariantObject *v = value->v4Value().asVariantObject()) { v->addVmePropertyReference(); - } else if (QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(v8::Handle<v8::Object>::Cast(value))) { + } else if (QV4::QObjectWrapper *wrapper = value->v4Value().asQObjectWrapper()) { // We need to track this QObject to signal its deletion - valueObject = r->object; + valueObject = wrapper->object; // Do we already have a QObject guard for this property? if (valueObject && !guard) { diff --git a/src/qml/qml/v4/qv4managed_p.h b/src/qml/qml/v4/qv4managed_p.h index 70c114375e..4cdbe4d6c5 100644 --- a/src/qml/qml/v4/qv4managed_p.h +++ b/src/qml/qml/v4/qv4managed_p.h @@ -79,6 +79,7 @@ class RegExp; struct Lookup; struct ExecutionEngine; struct VariantObject; +struct QObjectWrapper; struct ManagedVTable { @@ -164,6 +165,7 @@ public: Type_MathObject, Type_ForeachIteratorObject, Type_RegExp, + Type_QObject, // QML bindings Type_QmlLocale, @@ -197,6 +199,7 @@ public: JSONObject *asJSONObject() { return type == Type_JSONObject ? reinterpret_cast<JSONObject *>(this) : 0; } ForeachIteratorObject *asForeachIteratorObject() { return type == Type_ForeachIteratorObject ? reinterpret_cast<ForeachIteratorObject *>(this) : 0; } RegExp *asRegExp() { return type == Type_RegExp ? reinterpret_cast<RegExp *>(this) : 0; } + QObjectWrapper *asQObjectWrapper() { return type == Type_QObject ? reinterpret_cast<QObjectWrapper*>(this) : 0; } QQmlLocaleData *asQmlLocale() { return type == Type_QmlLocale ? reinterpret_cast<QQmlLocaleData *>(this) : 0; } diff --git a/src/qml/qml/v4/qv4value_p.h b/src/qml/qml/v4/qv4value_p.h index 6896e01b68..ea1f1f86d3 100644 --- a/src/qml/qml/v4/qv4value_p.h +++ b/src/qml/qml/v4/qv4value_p.h @@ -270,6 +270,7 @@ struct Q_QML_EXPORT Value ArrayObject *asArrayObject() const; ErrorObject *asErrorObject() const; VariantObject *asVariantObject() const; + QObjectWrapper *asQObjectWrapper() const; uint asArrayIndex() const; uint asArrayLength(bool *ok) const; @@ -547,6 +548,11 @@ inline VariantObject *Value::asVariantObject() const return isObject() ? managed()->asVariantObject() : 0; } +inline QObjectWrapper *Value::asQObjectWrapper() const +{ + return isObject() ? managed()->asQObjectWrapper() : 0; +} + // ### inline Value Managed::construct(ExecutionContext *context, Value *args, int argc) { return vtbl->construct(this, context, args, argc); diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 188c8e3ebc..e0a7766886 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -220,8 +220,6 @@ QVariant QV8Engine::toVariant(const QV4::Value &value, int typeHint) return QVariant(); case QV8ObjectResource::TypeType: return m_typeWrapper.toVariant(r); - case QV8ObjectResource::QObjectType: - return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r)); case QV8ObjectResource::ListType: return m_listWrapper.toVariant(r); case QV8ObjectResource::ValueTypeType: @@ -230,6 +228,8 @@ QVariant QV8Engine::toVariant(const QV4::Value &value, int typeHint) } else if (typeHint == QMetaType::QJsonObject && !value.asArrayObject() && !value.asFunctionObject()) { return QVariant::fromValue(jsonObjectFromJS(value)); + } else if (QV4::QObjectWrapper *wrapper = object->asQObjectWrapper()) { + return qVariantFromValue<QObject *>(wrapper->object); } else if (object->isListType()) return QV4::SequencePrototype::toVariant(object); } @@ -1290,20 +1290,17 @@ QObject *QV8Engine::qtObjectFromJS(const QV4::Value &value) if (!value.isObject()) return 0; - QV4::VariantObject *v = value.asVariantObject(); - if (v) { + + if (QV4::VariantObject *v = value.asVariantObject()) { QVariant variant = v->data; int type = variant.userType(); if (type == QMetaType::QObjectStar) return *reinterpret_cast<QObject* const *>(variant.constData()); } - QV8ObjectResource *r = (QV8ObjectResource *)v8::Value::fromV4Value(value)->ToObject()->GetExternalResource(); - if (!r) + QV4::QObjectWrapper *wrapper = value.asQObjectWrapper(); + if (!wrapper) return 0; - QV8ObjectResource::ResourceType type = r->resourceType(); - if (type == QV8ObjectResource::QObjectType) - return qobjectWrapper()->toQObject(r); - return 0; + return wrapper->object; } void QV8Engine::startTimer(const QString &timerName) diff --git a/src/qml/qml/v8/qv8objectresource_p.h b/src/qml/qml/v8/qv8objectresource_p.h index b4597fd928..4eaee31c81 100644 --- a/src/qml/qml/v8/qv8objectresource_p.h +++ b/src/qml/qml/v8/qv8objectresource_p.h @@ -69,7 +69,7 @@ class QV8ObjectResource : public v8::Object::ExternalResource { public: QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); } - enum ResourceType { ContextType, QObjectType, TypeType, ListType, + enum ResourceType { ContextType, TypeType, ListType, ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType, ListModelType, Context2DStyleType, Context2DPixelArrayType, ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType, diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 6f5cc97b55..2303df3116 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -75,6 +75,176 @@ QT_BEGIN_NAMESPACE # endif #endif + +using namespace QV4; + +QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) + : Object(engine) + , object(object) +{ + this->v8Engine = QV8Engine::get(engine->publicEngine); + type = Type_QObject; + vtbl = &static_vtbl; + initClass(engine); +} + +QObjectWrapper::~QObjectWrapper() +{ +} + +QV4::Value QObjectWrapper::method_toString(QV4::SimpleCallContext *ctx) +{ + QString result; + if (object) { + QString objectName = object->objectName(); + + result += QString::fromUtf8(object->metaObject()->className()); + result += QLatin1String("(0x"); + result += QString::number((quintptr)object.object(),16); + + if (!objectName.isEmpty()) { + result += QLatin1String(", \""); + result += objectName; + result += QLatin1Char('\"'); + } + + result += QLatin1Char(')'); + } else { + result = QLatin1String("null"); + } + + return QV4::Value::fromString(ctx, result); +} + +QV4::Value QObjectWrapper::method_destroy(QV4::SimpleCallContext *ctx) +{ + if (!object) + return QV4::Value::undefinedValue(); + QQmlData *ddata = QQmlData::get(object, false); + if (!ddata || ddata->indestructible || ddata->rootObjectInCreation) + ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); + + int delay = 0; + if (ctx->argumentCount > 0) + delay = ctx->arguments[0].toUInt32(); + + if (delay > 0) + QTimer::singleShot(delay, object, SLOT(deleteLater())); + else + object->deleteLater(); + + return QV4::Value::undefinedValue(); +} + +QV4::Value QObjectWrapper::get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty) +{ + QObjectWrapper *that = static_cast<QObjectWrapper*>(m); + + if (QQmlData::wasDeleted(that->object)) { + if (hasProperty) + *hasProperty = false; + return QV4::Value::undefinedValue(); + } + + QObject *object = that->object; + + QHashedV4String propertystring(QV4::Value::fromString(name)); + + QV8Engine *v8engine = that->v8Engine; + QQmlContextData *context = v8engine->callingContext(); + + v8::Handle<v8::Value> This = QV4::Value::fromObject(that); + v8::Handle<v8::Value> result = QV8QObjectWrapper::GetProperty(v8engine, object, &This, propertystring, + context, QV8QObjectWrapper::IgnoreRevision); + if (!result.IsEmpty()) { + if (hasProperty) + *hasProperty = true; + return result->v4Value(); + } + + if (name->startsWithUpper()) { + // Check for attached properties + if (context && context->imports) { + QQmlTypeNameCache::Result r = context->imports->query(propertystring); + + if (r.isValid()) { + if (r.scriptIndex != -1) { + return QV4::Value::undefinedValue(); + } else if (r.type) { + return v8engine->typeWrapper()->newObject(object, r.type, QV8TypeWrapper::ExcludeEnums)->v4Value(); + } else if (r.importNamespace) { + return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace, + QV8TypeWrapper::ExcludeEnums)->v4Value(); + } + Q_ASSERT(!"Unreachable"); + } + } + } + + return QV4::Object::get(m, ctx, name, hasProperty); +} + +void QObjectWrapper::put(Managed *m, ExecutionContext *ctx, String *name, const Value &value) +{ + QObjectWrapper *that = static_cast<QObjectWrapper*>(m); + + if (QQmlData::wasDeleted(that->object)) + return; + + QObject *object = that->object; + + QHashedV4String propertystring(QV4::Value::fromString(name)); + + QV8Engine *v8engine = that->v8Engine; + QQmlContextData *context = v8engine->callingContext(); + bool result = QV8QObjectWrapper::SetProperty(v8engine, object, propertystring, context, value, QV8QObjectWrapper::IgnoreRevision); + + if (!result) { + QString error = QLatin1String("Cannot assign to non-existent property \"") + + name->toQString() + QLatin1Char('\"'); + ctx->throwError(error); + } +} + +QV4::Value QObjectWrapper::enumerateProperties(Object *object) +{ + QObjectWrapper *that = static_cast<QObjectWrapper*>(object); + + if (that->object.isNull()) + return QV4::Value::undefinedValue(); + + QStringList result; + + QQmlEnginePrivate *ep = that->v8Engine->engine() + ? QQmlEnginePrivate::get(that->v8Engine->engine()) + : 0; + + QQmlPropertyCache *cache = 0; + QQmlData *ddata = QQmlData::get(that->object); + if (ddata) + cache = ddata->propertyCache; + + if (!cache) { + cache = ep ? ep->cache(that->object) : 0; + if (cache) { + if (ddata) { cache->addref(); ddata->propertyCache = cache; } + } else { + // Not cachable - fall back to QMetaObject (eg. dynamic meta object) + const QMetaObject *mo = that->object->metaObject(); + int pc = mo->propertyCount(); + int po = mo->propertyOffset(); + for (int i=po; i<pc; ++i) + result << QString::fromUtf8(mo->property(i).name()); + } + } else { + result = cache->propertyNames(); + } + + return QV4::Value::fromObject(that->engine()->newArrayObject(result)); +} + +DEFINE_MANAGED_VTABLE(QObjectWrapper); + #define QOBJECT_TOSTRING_INDEX -2 #define QOBJECT_DESTROY_INDEX -3 @@ -175,11 +345,6 @@ private: }; } -QV8QObjectResource::QV8QObjectResource(QV8Engine *engine, QObject *object) -: QV8ObjectResource(engine), object(object) -{ -} - QV8SignalHandlerResource::QV8SignalHandlerResource(QV8Engine *engine, QObject *object, int index) : QV8ObjectResource(engine), object(object), index(index) { @@ -207,11 +372,11 @@ void QV8QObjectWrapper::destroy() qDeleteAll(m_connections); m_connections.clear(); - QIntrusiveList<QV8QObjectResource, &QV8QObjectResource::weakResource>::iterator i = m_javaScriptOwnedWeakQObjects.begin(); + QIntrusiveList<QV4::QObjectWrapper, &QV4::QObjectWrapper::weakResource>::iterator i = m_javaScriptOwnedWeakQObjects.begin(); for (; i != m_javaScriptOwnedWeakQObjects.end(); ++i) { - QV8QObjectResource *resource = *i; - Q_ASSERT(resource); - deleteWeakQObject(resource, true); + QV4::QObjectWrapper *wrapper = *i; + Q_ASSERT(wrapper); + deleteWeakQObject(wrapper, true); } } @@ -261,45 +426,6 @@ static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, double v) static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *e, QObject *v) { return e->newQObject(v); } -template<typename T, void (*ReadFunction)(QObject *, const QQmlPropertyData &, - void *, QQmlNotifier **)> -static v8::Handle<v8::Value> GenericValueGetter(v8::Handle<v8::String>, const v8::AccessorInfo &info) -{ - v8::Handle<v8::Object> This = info.This(); - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This); - - QObject *object = resource->object; - if (QQmlData::wasDeleted(object)) return QV4::Value::undefinedValue(); - - QQmlPropertyData *property = - (QQmlPropertyData *)v8::External::Cast(info.Data().get())->Value(); - - QQmlEngine *engine = resource->engine->engine(); - QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0; - - T value = T(); - - if (ep && ep->propertyCapture) { - if (ReadFunction == ReadAccessor::Accessor && property->accessors->notifier) { - QQmlNotifier *notifier = 0; - ReadFunction(object, *property, &value, ¬ifier); - if (notifier) ep->captureProperty(notifier); - } else if (!property->isConstant()) { - ep->captureProperty(object, property->coreIndex, property->notifyIndex); - ReadFunction(object, *property, &value, 0); - } else { - ReadFunction(object, *property, &value, 0); - } - } else { - ReadFunction(object, *property, &value, 0); - } - - return valueToHandle(resource->engine, value); -} - -#define FAST_GETTER_FUNCTION(property, cpptype) \ - (property->hasAccessors()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Accessor>):(property->isDirect()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Direct>):((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Indirect>))) - static quint32 toStringHash = quint32(-1); static quint32 destroyHash = quint32(-1); @@ -319,12 +445,6 @@ void QV8QObjectWrapper::init(QV8Engine *engine) destroyHash = m_destroyString.hash(); { - v8::Handle<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator); - ft->InstanceTemplate()->SetHasExternalResource(true); - m_constructor = ft->GetFunction()->v4Value(); - } - { #define CREATE_FUNCTION_SOURCE \ "(function(method) { "\ "return (function(object, data, qmlglobal) { "\ @@ -363,20 +483,13 @@ void QV8QObjectWrapper::init(QV8Engine *engine) bool QV8QObjectWrapper::isQObject(v8::Handle<v8::Object> obj) { - return v8_resource_cast<QV8QObjectResource>(obj) != 0; + return obj->v4Value().asQObjectWrapper() != 0; } QObject *QV8QObjectWrapper::toQObject(v8::Handle<v8::Object> obj) { - QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(obj); - return r?r->object:0; -} - -// r *MUST* be a QV8ObjectResource (r->type() == QV8ObjectResource::QObjectType) -QObject *QV8QObjectWrapper::toQObject(QV8ObjectResource *r) -{ - Q_ASSERT(r->resourceType() == QV8ObjectResource::QObjectType); - return static_cast<QV8QObjectResource *>(r)->object; + QV4::QObjectWrapper *wrapper = obj->v4Value().asQObjectWrapper(); + return wrapper?wrapper->object:0; } // Load value properties @@ -744,155 +857,15 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH return true; } -v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Handle<v8::String> property, - const v8::AccessorInfo &info) -{ - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - - if (QQmlData::wasDeleted(resource->object)) - return v8::Handle<v8::Value>(); - - QObject *object = resource->object; - - QHashedV4String propertystring(property->v4Value()); - - QV8Engine *v8engine = resource->engine; - QQmlContextData *context = v8engine->callingContext(); - - v8::Handle<v8::Value> This = info.This(); - v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring, - context, QV8QObjectWrapper::IgnoreRevision); - if (!result.IsEmpty()) - return result; - - if (property->v4Value().asString()->startsWithUpper()) { - // Check for attached properties - if (context && context->imports) { - QQmlTypeNameCache::Result r = context->imports->query(propertystring); - - if (r.isValid()) { - if (r.scriptIndex != -1) { - return QV4::Value::undefinedValue(); - } else if (r.type) { - return v8engine->typeWrapper()->newObject(object, r.type, QV8TypeWrapper::ExcludeEnums); - } else if (r.importNamespace) { - return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace, - QV8TypeWrapper::ExcludeEnums); - } - Q_ASSERT(!"Unreachable"); - } - } - } - - return v8::Handle<v8::Value>(); -} - -v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Handle<v8::String> property, - v8::Handle<v8::Value> value, - const v8::AccessorInfo &info) -{ - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - - if (QQmlData::wasDeleted(resource->object)) - return value; - - QObject *object = resource->object; - - QHashedV4String propertystring(property->v4Value()); - - QV8Engine *v8engine = resource->engine; - QQmlContextData *context = v8engine->callingContext(); - bool result = SetProperty(v8engine, object, propertystring, context, value, QV8QObjectWrapper::IgnoreRevision); - - if (!result) { - QString error = QLatin1String("Cannot assign to non-existent property \"") + - property->v4Value().toQString() + QLatin1Char('\"'); - v8::ThrowException(v8::Exception::Error(v8engine->toString(error))); - return value; - } - - return value; -} - -v8::Handle<v8::Value> QV8QObjectWrapper::Query(v8::Handle<v8::String> property, - const v8::AccessorInfo &info) -{ - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - - if (resource->object.isNull()) - return v8::Handle<v8::Value>(); - - QV8Engine *engine = resource->engine; - QObject *object = resource->object; - QQmlContextData *context = engine->callingContext(); - - QHashedV4String propertystring(property->v4Value()); - - QQmlPropertyData local; - QQmlPropertyData *result = 0; - result = QQmlPropertyCache::property(engine->engine(), object, propertystring, context, local); - - if (!result) - return v8::Handle<v8::Value>(); - else if (!result->isWritable() && !result->isQList()) - return QV4::Value::fromInt32(v8::ReadOnly | v8::DontDelete); - else - return QV4::Value::fromInt32(v8::DontDelete); -} - -v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info) -{ - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); - - if (resource->object.isNull()) - return v8::Array::New(); - - QObject *object = resource->object; - - QStringList result; - - QQmlEnginePrivate *ep = resource->engine->engine() - ? QQmlEnginePrivate::get(resource->engine->engine()) - : 0; - - QQmlPropertyCache *cache = 0; - QQmlData *ddata = QQmlData::get(object); - if (ddata) - cache = ddata->propertyCache; - - if (!cache) { - cache = ep ? ep->cache(object) : 0; - if (cache) { - if (ddata) { cache->addref(); ddata->propertyCache = cache; } - } else { - // Not cachable - fall back to QMetaObject (eg. dynamic meta object) - const QMetaObject *mo = object->metaObject(); - int pc = mo->propertyCount(); - int po = mo->propertyOffset(); - for (int i=po; i<pc; ++i) - result << QString::fromUtf8(mo->property(i).name()); - } - } else { - result = cache->propertyNames(); - } - - v8::Handle<v8::Array> rv = v8::Array::New(result.count()); - - for (int ii = 0; ii < result.count(); ++ii) - rv->Set(ii, resource->engine->toString(result.at(ii))); - - return rv; -} - static void FastValueSetter(v8::Handle<v8::String>, v8::Handle<v8::Value> value, const v8::AccessorInfo& info) { - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); + QV4::QObjectWrapper *wrapper = info.This()->v4Value().asQObjectWrapper(); - if (QQmlData::wasDeleted(resource->object)) + if (QQmlData::wasDeleted(wrapper->object)) return; - QObject *object = resource->object; + QObject *object = wrapper->object; QQmlPropertyData *property = (QQmlPropertyData *)v8::External::Cast(info.Data().get())->Value(); @@ -908,18 +881,18 @@ static void FastValueSetter(v8::Handle<v8::String>, v8::Handle<v8::Value> value, Q_ASSERT(pdata->isWritable() || pdata->isQList()); - StoreProperty(resource->engine, object, pdata, value); + StoreProperty(wrapper->v8Engine, object, pdata, value); } static void FastValueSetterReadOnly(v8::Handle<v8::String> property, v8::Handle<v8::Value>, const v8::AccessorInfo& info) { - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This()); + QV4::QObjectWrapper *wrapper = info.This()->v4Value().asQObjectWrapper(); - if (QQmlData::wasDeleted(resource->object)) + if (QQmlData::wasDeleted(wrapper->object)) return; - QV8Engine *v8engine = resource->engine; + QV8Engine *v8engine = wrapper->v8Engine; QString error = QLatin1String("Cannot assign to read-only property \"") + property->v4Value().toQString() + QLatin1Char('\"'); @@ -929,15 +902,14 @@ static void FastValueSetterReadOnly(v8::Handle<v8::String> property, v8::Handle< void QV8QObjectWrapper::WeakQObjectReferenceCallback(QV4::PersistentValue &handle, void *wrapper) { Q_ASSERT(handle.value().isObject()); - v8::Handle<v8::Object> v8object = handle.value(); - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(v8object); - Q_ASSERT(resource); + QV4::QObjectWrapper *wrappedObject = handle.value().asQObjectWrapper(); + Q_ASSERT(wrappedObject); + Q_ASSERT(wrapper); - static_cast<QV8QObjectWrapper*>(wrapper)->unregisterWeakQObjectReference(resource); - if (static_cast<QV8QObjectWrapper*>(wrapper)->deleteWeakQObject(resource, false)) { + static_cast<QV8QObjectWrapper*>(wrapper)->unregisterWeakQObjectReference(wrappedObject); + if (static_cast<QV8QObjectWrapper*>(wrapper)->deleteWeakQObject(wrappedObject, false)) { // dispose - v8object->SetExternalResource(0); - delete resource; + delete wrappedObject; handle.clear(); } else { // ### FIXME @@ -945,129 +917,16 @@ void QV8QObjectWrapper::WeakQObjectReferenceCallback(QV4::PersistentValue &handl } } -v8::Handle<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *engine) -{ - Q_ASSERT(object); - Q_ASSERT(this->engine); - - Q_ASSERT(QQmlData::get(object, false)); - Q_ASSERT(QQmlData::get(object, false)->propertyCache == this); - - // Setup constructor - if (constructor.isEmpty()) { - v8::Handle<v8::FunctionTemplate> ft; - - const QHashedString toString(QStringLiteral("toString")); - const QHashedString destroy(QStringLiteral("destroy")); - - // As we use hash linking, or with property overrides, it is possible that iterating - // over the values can yield duplicates. To combat this, we must unique'ify our properties. - const bool checkForDuplicates = stringCache.isLinked() || _hasPropertyOverrides; - - StringCache uniqueHash; - if (checkForDuplicates) - uniqueHash.reserve(stringCache.count()); - - // XXX TODO: Enables fast property accessors. These more than double the property access - // performance, but the cost of setting up this structure hasn't been measured so - // its not guaranteed that this is a win overall. We need to try and measure the cost. - for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) { - if (iter.equals(toString) || iter.equals(destroy)) - continue; - - if (checkForDuplicates) { - if (uniqueHash.contains(iter)) - continue; - uniqueHash.insert(iter); - } - - QQmlPropertyData *property = (*iter).second; - if (property->notFullyResolved()) resolve(property); - - if (property->isFunction()) - continue; - - v8::AccessorGetter fastgetter = 0; - - if (property->isQObject()) - fastgetter = FAST_GETTER_FUNCTION(property, QObject*); - else if (property->propType == QMetaType::Int || property->isEnum()) - fastgetter = FAST_GETTER_FUNCTION(property, int); - else if (property->propType == QMetaType::Bool) - fastgetter = FAST_GETTER_FUNCTION(property, bool); - else if (property->propType == QMetaType::QString) - fastgetter = FAST_GETTER_FUNCTION(property, QString); - else if (property->propType == QMetaType::UInt) - fastgetter = FAST_GETTER_FUNCTION(property, uint); - else if (property->propType == QMetaType::Float) - fastgetter = FAST_GETTER_FUNCTION(property, float); - else if (property->propType == QMetaType::Double) - fastgetter = FAST_GETTER_FUNCTION(property, double); - - if (fastgetter) { - if (ft.IsEmpty()) { - ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter, - QV8QObjectWrapper::Setter, - QV8QObjectWrapper::Query, - 0, - QV8QObjectWrapper::Enumerator); - ft->InstanceTemplate()->SetHasExternalResource(true); - } - - v8::AccessorSetter fastsetter = FastValueSetter; - if (!property->isWritable()) - fastsetter = FastValueSetterReadOnly; - - // We wrap the raw QQmlPropertyData pointer here. This is safe as the - // pointer will remain valid at least as long as the lifetime of any QObject's of - // this type and the property accessor checks if the object is 0 (deleted) before - // dereferencing the pointer. - ft->InstanceTemplate()->SetAccessor(engine->toString(iter.key()), fastgetter, fastsetter, - v8::External::New(property)); - } - } - - if (ft.IsEmpty()) { - constructor = engine->qobjectWrapper()->m_constructor; - } else { - ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter, - QV8QObjectWrapper::Setter, - QV8QObjectWrapper::Query, - 0, - QV8QObjectWrapper::Enumerator); - ft->InstanceTemplate()->SetHasExternalResource(true); - constructor = ft->GetFunction()->v4Value(); - } - - QQmlCleanup::addToEngine(this->engine); - } - - v8::Handle<v8::Object> result = constructor.value().asFunctionObject()->newInstance(); - QV8QObjectResource *r = new QV8QObjectResource(engine, object); - result->SetExternalResource(r); - return result; -} - v8::Handle<v8::Object> QV8QObjectWrapper::newQObject(QObject *object, QQmlData *ddata, QV8Engine *engine) { - v8::Handle<v8::Object> rv; - if (!ddata->propertyCache && engine->engine()) { ddata->propertyCache = QQmlEnginePrivate::get(engine->engine())->cache(object); if (ddata->propertyCache) ddata->propertyCache->addref(); } - if (ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine->engine()) { - rv = ddata->propertyCache->newQObject(object, engine); - } else { - // XXX NewInstance() should be optimized - rv = m_constructor.value().asFunctionObject()->newInstance(); - QV8QObjectResource *r = new QV8QObjectResource(engine, object); - rv->SetExternalResource(r); - } - - return rv; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QV4::QObjectWrapper *wrapper = new (v4->memoryManager) QV4::QObjectWrapper(v4, object); + return QV4::Value::fromObject(wrapper); } /* @@ -1107,8 +966,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object) // ### FIXME //ddata->v8object.MakeWeak(this, WeakQObjectReferenceCallback); ddata->v8objectid = m_id; - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(rv); - registerWeakQObjectReference(resource); + QV4::QObjectWrapper *wrapper = rv->v4Value().asQObjectWrapper(); + // ### FIXME: registerWeakQObjectReference(wrapper); return rv; } else { @@ -1126,8 +985,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object) // ### FIXME //ddata->v8object.MakeWeak(this, WeakQObjectReferenceCallback); ddata->v8objectid = m_id; - QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(rv); - registerWeakQObjectReference(resource); + QV4::QObjectWrapper *wrapper = rv->v4Value().asQObjectWrapper(); + // ### FIXME registerWeakQObjectReference(wrapper); if (found) { delete (*iter); @@ -1155,9 +1014,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object) // returns true if the object's qqmldata v8object handle should // be disposed by the caller, false if it should not be (due to // creation status, etc). -bool QV8QObjectWrapper::deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor) +bool QV8QObjectWrapper::deleteWeakQObject(QObjectWrapper *wrapper, bool calledFromEngineDtor) { - QObject *object = resource->object; + QObject *object = wrapper->object; if (object) { QQmlData *ddata = QQmlData::get(object, false); if (ddata) { @@ -1708,15 +1567,17 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType) return 10; } - QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource()); - if (r && r->resourceType() == QV8ObjectResource::QObjectType) { + if (obj->v4Value().asQObjectWrapper()) { switch (conversionType) { case QMetaType::QObjectStar: return 0; default: return 10; } - } else if (r && r->resourceType() == QV8ObjectResource::ValueTypeType) { + } + + QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource()); + if (r && r->resourceType() == QV8ObjectResource::ValueTypeType) { if (r->engine->toVariant(actual->v4Value(), -1).userType() == conversionType) return 0; return 10; @@ -1966,23 +1827,23 @@ QV4::Value QV8QObjectWrapper::Invoke(const v8::Arguments &args) Q_ASSERT(args.Length() == 5); Q_ASSERT(args[0]->IsObject()); - QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(args[0]->ToObject()); + QV4::QObjectWrapper *wrapper = args[0]->v4Value().asQObjectWrapper(); - if (!resource) + if (!wrapper) return QV4::Value::undefinedValue(); int argCount = args[3]->Int32Value(); v8::Handle<v8::Object> arguments = v8::Handle<v8::Object>::Cast(args[4]); // Special hack to return info about this closure. - if (argCount == 1 && arguments->Get(0)->StrictEquals(resource->engine->qobjectWrapper()->m_hiddenObject.value())) { + if (argCount == 1 && arguments->Get(0)->StrictEquals(wrapper->v8Engine->qobjectWrapper()->m_hiddenObject.value())) { v8::Handle<v8::Array> data = v8::Array::New(2); data->Set(0, args[0]); data->Set(1, args[1]); return data->v4Value(); } - QObject *object = resource->object; + QObject *object = wrapper->object; int index = args[1]->Int32Value(); if (!object) @@ -1991,9 +1852,9 @@ QV4::Value QV8QObjectWrapper::Invoke(const v8::Arguments &args) if (index < 0) { // Builtin functions if (index == QOBJECT_TOSTRING_INDEX) { - return ToString(resource->engine, object, argCount, arguments); + return ToString(wrapper->v8Engine, object, argCount, arguments); } else if (index == QOBJECT_DESTROY_INDEX) { - return Destroy(resource->engine, object, argCount, arguments); + return Destroy(wrapper->v8Engine, object, argCount, arguments); } else { return QV4::Value::undefinedValue(); } @@ -2022,8 +1883,8 @@ QV4::Value QV8QObjectWrapper::Invoke(const v8::Arguments &args) v8::Handle<v8::Value> qmlglobal = args[2]; QQmlV4Function func(argCount, arguments->v4Value(), &rv, qmlglobal->v4Value(), - resource->engine->contextWrapper()->context(qmlglobal), - resource->engine); + wrapper->v8Engine->contextWrapper()->context(qmlglobal), + wrapper->v8Engine); QQmlV4Function *funcptr = &func; void *args[] = { 0, &funcptr }; @@ -2034,9 +1895,9 @@ QV4::Value QV8QObjectWrapper::Invoke(const v8::Arguments &args) CallArgs callArgs(argCount, &arguments); if (!method.isOverload()) { - return CallPrecise(object, method, resource->engine, callArgs); + return CallPrecise(object, method, wrapper->v8Engine, callArgs); } else { - return CallOverloaded(object, method, resource->engine, callArgs); + return CallOverloaded(object, method, wrapper->v8Engine, callArgs); } } @@ -2266,5 +2127,7 @@ QV4::Value CallArgument::toValue(QV8Engine *engine) } } +#include "qv8qobjectwrapper_p_jsclass.cpp" + QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h index 426f1225f1..e5db6035a7 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper_p.h +++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h @@ -65,6 +65,7 @@ #include "qv8objectresource_p.h" #include <private/qv4value_p.h> +#include <private/qv4object_p.h> QT_BEGIN_NAMESPACE @@ -76,17 +77,38 @@ class QV8QObjectInstance; class QV8QObjectConnectionList; class QQmlPropertyCache; -class QV8QObjectResource : public QV8ObjectResource -{ - V8_RESOURCE_TYPE(QObjectType); +namespace QV4 { -public: - QV8QObjectResource(QV8Engine *engine, QObject *object); +struct QV4_JS_CLASS(QObjectWrapper) : public QV4::Object +{ + QObjectWrapper(ExecutionEngine *v8Engine, QObject *object); + ~QObjectWrapper(); + QV8Engine *v8Engine; // ### Remove again. QQmlGuard<QObject> object; QIntrusiveListNode weakResource; + + QV4::Value method_toString(QV4::SimpleCallContext *ctx); + QV4::Value method_destroy(QV4::SimpleCallContext *ctx); + +private: + void initClass(QV4::ExecutionEngine *engine); + + static Value get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty); + static void put(Managed *m, ExecutionContext *ctx, String *name, const Value &value); + + static Value enumerateProperties(Object *object); + + static void destroy(Managed *that) + { + static_cast<QObjectWrapper *>(that)->~QObjectWrapper(); + } + + static const QV4::ManagedVTable static_vtbl; }; +} + class Q_QML_PRIVATE_EXPORT QV8QObjectWrapper { public: @@ -99,41 +121,33 @@ public: v8::Handle<v8::Value> newQObject(QObject *object); bool isQObject(v8::Handle<v8::Object>); QObject *toQObject(v8::Handle<v8::Object>); - static QObject *toQObject(QV8ObjectResource *); enum RevisionMode { IgnoreRevision, CheckRevision }; inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV4String &, QQmlContextData *, RevisionMode); inline bool setProperty(QObject *, const QHashedV4String &, QQmlContextData *, v8::Handle<v8::Value>, RevisionMode); - void registerWeakQObjectReference(QV8QObjectResource *resource) + void registerWeakQObjectReference(QV4::QObjectWrapper *wrapper) { - m_javaScriptOwnedWeakQObjects.insert(resource); + m_javaScriptOwnedWeakQObjects.insert(wrapper); } - void unregisterWeakQObjectReference(QV8QObjectResource *resource) + void unregisterWeakQObjectReference(QV4::QObjectWrapper *wrapper) { - m_javaScriptOwnedWeakQObjects.remove(resource); + m_javaScriptOwnedWeakQObjects.remove(wrapper); } private: friend class QQmlPropertyCache; friend class QV8QObjectConnectionList; friend class QV8QObjectInstance; + friend class QV4::QObjectWrapper; v8::Handle<v8::Object> newQObject(QObject *, QQmlData *, QV8Engine *); - bool deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor = false); + bool deleteWeakQObject(QV4::QObjectWrapper *wrapper, bool calledFromEngineDtor = false); static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *, const QHashedV4String &, QQmlContextData *, QV8QObjectWrapper::RevisionMode); static bool SetProperty(QV8Engine *, QObject *, const QHashedV4String &, QQmlContextData *, v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode); - static v8::Handle<v8::Value> Getter(v8::Handle<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> Setter(v8::Handle<v8::String> property, - v8::Handle<v8::Value> value, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> Query(v8::Handle<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info); static QV4::Value Connect(const v8::Arguments &args); static QV4::Value Disconnect(const v8::Arguments &args); static QV4::Value Invoke(const v8::Arguments &args); @@ -143,7 +157,6 @@ private: QV8Engine *m_engine; quint32 m_id; - QV4::PersistentValue m_constructor; QV4::PersistentValue m_methodConstructor; QV4::PersistentValue m_signalHandlerConstructor; QV4::PersistentValue m_toStringSymbol; @@ -154,7 +167,7 @@ private: QHash<QObject *, QV8QObjectConnectionList *> m_connections; typedef QHash<QObject *, QV8QObjectInstance *> TaintedHash; TaintedHash m_taintedObjects; - QIntrusiveList<QV8QObjectResource, &QV8QObjectResource::weakResource> m_javaScriptOwnedWeakQObjects; + QIntrusiveList<QV4::QObjectWrapper, &QV4::QObjectWrapper::weakResource> m_javaScriptOwnedWeakQObjects; }; v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV4String &string, diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index ab8f8eab6e..f51537bedf 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -32,3 +32,5 @@ SOURCES += \ $$PWD/qv4sqlerrors.cpp \ $$PWD/qqmlbuiltinfunctions.cpp +JS_CLASS_SOURCES += \ + $$PWD/qv8qobjectwrapper_p.h diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 6666f63387..98d828c382 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -453,9 +453,8 @@ void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QVector<int QDateTime dt = propertyValue->v4Value().asDateObject()->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); } else if (propertyValue->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); - if (r && r->resourceType() == QV8ObjectResource::QObjectType) { - QObject *o = QV8QObjectWrapper::toQObject(r); + if (QV4::QObjectWrapper *wrapper = propertyValue->v4Value().asQObjectWrapper()) { + QObject *o = wrapper->object; const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); if (role.type == ListLayout::Role::QObject) roleIndex = e->setQObjectProperty(role, o); @@ -529,9 +528,8 @@ void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QV8Engine * e->setDateTimePropertyFast(r, dt); } } else if (propertyValue->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); - if (r && r->resourceType() == QV8ObjectResource::QObjectType) { - QObject *o = QV8QObjectWrapper::toQObject(r); + if (QV4::QObjectWrapper *wrapper = propertyValue->v4Value().asQObjectWrapper()) { + QObject *o = wrapper->object; const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); if (r.type == ListLayout::Role::QObject) e->setQObjectPropertyFast(r, o); @@ -1190,9 +1188,9 @@ int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Valu QDateTime dt = d->v4Value().asDateObject()->toQDateTime();; roleIndex = setDateTimeProperty(role, dt); } else if (d->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *) d->ToObject()->GetExternalResource(); - if (role.type == ListLayout::Role::QObject && r && r->resourceType() == QV8ObjectResource::QObjectType) { - QObject *o = QV8QObjectWrapper::toQObject(r); + QV4::QObjectWrapper *wrapper = d->v4Value().asQObjectWrapper(); + if (role.type == ListLayout::Role::QObject && wrapper) { + QObject *o = wrapper->object; roleIndex = setQObjectProperty(role, o); } else if (role.type == ListLayout::Role::VariantMap) { roleIndex = setVariantMapProperty(role, d->ToObject(), eng); |