From 3011eb517e352faa614107fcf7cc756991dbf16c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 7 Jun 2013 07:53:21 +0200 Subject: [PATCH] Convert the qml adapter model to v4 Change-Id: Ief02791fd5391653477b0a6031a5e8e644afcfd4 Reviewed-by: Simon Hausmann --- src/qml/qml/v4/qv4functionobject.cpp | 33 +++++++ src/qml/qml/v4/qv4functionobject_p.h | 26 +++++ src/qml/util/qqmladaptormodel.cpp | 184 ++++++++++++++++------------------- 3 files changed, 145 insertions(+), 98 deletions(-) diff --git a/src/qml/qml/v4/qv4functionobject.cpp b/src/qml/qml/v4/qv4functionobject.cpp index 7fde827..604b559 100644 --- a/src/qml/qml/v4/qv4functionobject.cpp +++ b/src/qml/qml/v4/qv4functionobject.cpp @@ -446,6 +446,39 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V return result; } +Value IndexedBuiltinFunction::call(Managed *that, ExecutionContext *context, const Value &thisObject, Value *args, int argc) +{ + IndexedBuiltinFunction *f = static_cast(that); + + SimpleCallContext ctx; + ctx.initSimpleCallContext(f->scope->engine); + ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? + ctx.thisObject = thisObject; + ctx.arguments = args; + ctx.argumentCount = argc; + context->engine->pushContext(&ctx); + + if (!f->strictMode && !thisObject.isObject()) { + // Built-in functions allow for the this object to be null or undefined. This overrides + // the behaviour of changing thisObject to the global object if null/undefined and allows + // the built-in functions for example to throw a type error if null is passed. + if (!thisObject.isUndefined() && !thisObject.isNull()) + ctx.thisObject = Value::fromObject(thisObject.toObject(context)); + } + + Value result = Value::undefinedValue(); + try { + result = f->code(&ctx, f->index); + } catch (Exception &ex) { + ex.partiallyUnwindContext(context); + throw; + } + + context->engine->popContext(); + return result; +} + +DEFINE_MANAGED_VTABLE(IndexedBuiltinFunction); DEFINE_MANAGED_VTABLE(BoundFunction); diff --git a/src/qml/qml/v4/qv4functionobject_p.h b/src/qml/qml/v4/qv4functionobject_p.h index 1d04306..b2cc829 100644 --- a/src/qml/qml/v4/qv4functionobject_p.h +++ b/src/qml/qml/v4/qv4functionobject_p.h @@ -169,6 +169,32 @@ protected: static const ManagedVTable static_vtbl; }; +struct IndexedBuiltinFunction: FunctionObject +{ + Q_MANAGED + + Value (*code)(SimpleCallContext *ctx, uint index); + uint index; + + IndexedBuiltinFunction(ExecutionContext *scope, uint index, Value (*code)(SimpleCallContext *ctx, uint index)) + : FunctionObject(scope, name) + , code(code) + , index(index) + { + vtbl = &static_vtbl; + isBuiltinFunction = true; + } + + static Value construct(Managed *, ExecutionContext *ctx, Value *, int) + { + ctx->throwTypeError(); + return Value::undefinedValue(); + } + + static Value call(Managed *that, ExecutionContext *ctx, const Value &thisObject, Value *args, int argc); +}; + + struct ScriptFunction: FunctionObject { ScriptFunction(ExecutionContext *scope, Function *function); diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 5fa6d31..bf93c78 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -54,43 +54,20 @@ QT_BEGIN_NAMESPACE class QQmlAdaptorModelEngineData : public QV8Engine::Deletable { public: - enum - { - Index, - ModelData, - HasModelChildren, - StringCount - }; - QQmlAdaptorModelEngineData(QV8Engine *engine); ~QQmlAdaptorModelEngineData(); - v8::Handle index() { - QV4::Object *o = strings.value().asObject(); - QV4::ExecutionContext *ctx = o->engine()->current; - return QV4::Value::fromString(o->getIndexed(Index).toString(ctx)); - } - v8::Handle modelData() { - QV4::Object *o = strings.value().asObject(); - QV4::ExecutionContext *ctx = o->engine()->current; - return QV4::Value::fromString(o->getIndexed(ModelData).toString(ctx)); - } - v8::Handle hasModelChildren() { - QV4::Object *o = strings.value().asObject(); - QV4::ExecutionContext *ctx = o->engine()->current; - return QV4::Value::fromString(o->getIndexed(HasModelChildren).toString(ctx)); - } - - QV4::PersistentValue constructorListItem; - QV4::PersistentValue strings; + QV4::ExecutionEngine *v4; + QV4::PersistentValue listItemProto; }; V8_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData) -static v8::Handle get_index(v8::Handle, const v8::AccessorInfo &info) +static QV4::Value get_index(QV4::SimpleCallContext *ctx) { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE(data, "Not a valid VisualData object"); + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); return QV4::Value::fromInt32(data->index); } @@ -130,9 +107,8 @@ public: void setValue(const QString &role, const QVariant &value); bool resolveIndex(const QQmlAdaptorModel &model, int idx); - static v8::Handle get_property(v8::Handle, const v8::AccessorInfo &info); - static void set_property( - v8::Handle, v8::Handle value, const v8::AccessorInfo &info); + static QV4::Value get_property(QV4::SimpleCallContext *ctx, uint propertyId); + static QV4::Value set_property(QV4::SimpleCallContext *ctx, uint propertyId); VDMModelDelegateDataType *type; QVector cachedData; @@ -218,23 +194,45 @@ public: dataType->watchedRoles += newRoles; } + static QV4::Value get_hasModelChildren(QV4::SimpleCallContext *ctx) + { + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + + const QQmlAdaptorModel *const model = static_cast(data)->type->model; + if (data->index >= 0 && *model) { + const QAbstractItemModel * const aim = model->aim(); + return QV4::Value::fromBoolean(aim->hasChildren(aim->index(data->index, 0, model->rootIndex))); + } else { + return QV4::Value::fromBoolean(false); + } + } + + void initializeConstructor(QQmlAdaptorModelEngineData *const data) { - constructor = v8::ObjectTemplate::New().get(); - constructor->SetHasExternalResource(true); - constructor->SetAccessor(data->index(), get_index); + QV4::ExecutionEngine *v4 = data->v4; + QV4::Object *proto = v4->newObject(); + QV4::Property *p = proto->insertMember(v4->newString(QStringLiteral("index")), + QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id_undefined, get_index)); + + p = proto->insertMember(v4->newString(QStringLiteral("hasModelChildren")), + QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id_undefined, get_hasModelChildren)); typedef QHash::const_iterator iterator; for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) { const int propertyId = propertyRoles.indexOf(it.value()); const QByteArray &propertyName = it.key(); - constructor->SetAccessor( - v8::String::New(propertyName.constData(), propertyName.length()), - QQmlDMCachedModelData::get_property, - QQmlDMCachedModelData::set_property, - QV4::Value::fromInt32(propertyId)); + p = proto->insertMember(v4->newString(QString::fromUtf8(propertyName)), + QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); + p->setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property)); + p->setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property)); } + prototype = QV4::Value::fromObject(proto); } // QAbstractDynamicMetaObject @@ -249,7 +247,7 @@ public: return static_cast(object)->metaCall(call, id, arguments); } - QExplicitlySharedDataPointer constructor; + QV4::PersistentValue prototype; QList propertyRoles; QList watchedRoleIds; QList watchedRoles; @@ -343,14 +341,13 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx) } } -v8::Handle QQmlDMCachedModelData::get_property( - v8::Handle, const v8::AccessorInfo &info) +QV4::Value QQmlDMCachedModelData::get_property(QV4::SimpleCallContext *ctx, uint propertyId) { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE(data, "Not a valid VisualData object"); + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); QQmlDMCachedModelData *modelData = static_cast(data); - const int propertyId = info.Data()->Int32Value(); if (data->index == -1) { if (!modelData->cachedData.isEmpty()) { return data->engine->fromVariant( @@ -363,21 +360,22 @@ v8::Handle QQmlDMCachedModelData::get_property( return QV4::Value::undefinedValue(); } -void QQmlDMCachedModelData::set_property( - v8::Handle, v8::Handle value, const v8::AccessorInfo &info) +QV4::Value QQmlDMCachedModelData::set_property(QV4::SimpleCallContext *ctx, uint propertyId) { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE_SETTER(data, "Not a valid VisualData object"); + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + if (!ctx->argumentCount) + ctx->throwTypeError(); - const int propertyId = info.Data()->Int32Value(); if (data->index == -1) { QQmlDMCachedModelData *modelData = static_cast(data); if (!modelData->cachedData.isEmpty()) { if (modelData->cachedData.count() > 1) { - modelData->cachedData[propertyId] = data->engine->toVariant(value->v4Value(), QVariant::Invalid); + modelData->cachedData[propertyId] = data->engine->toVariant(ctx->arguments[0], QVariant::Invalid); QMetaObject::activate(data, data->metaObject(), propertyId, 0); } else if (modelData->cachedData.count() == 1) { - modelData->cachedData[0] = data->engine->toVariant(value->v4Value(), QVariant::Invalid); + modelData->cachedData[0] = data->engine->toVariant(ctx->arguments[0], QVariant::Invalid); QMetaObject::activate(data, data->metaObject(), 0, 0); QMetaObject::activate(data, data->metaObject(), 1, 0); } @@ -425,29 +423,17 @@ public: QV4::Value get() { - if (!type->constructor) { + if (type->prototype.isEmpty()) { QQmlAdaptorModelEngineData * const data = engineData(engine); type->initializeConstructor(data); - type->constructor->SetAccessor(data->hasModelChildren(), get_hasModelChildren); } - v8::Handle data = type->constructor->NewInstance(); - data->SetExternalResource(this); + QV4::Object *proto = type->prototype.value().asObject(); + QV4::Object *o = proto->engine()->newObject(); + o->prototype = proto; + QV4::Value data = QV4::Value::fromObject(o); + v8::Handle(data)->SetExternalResource(this); ++scriptRef; - return data->v4Value(); - } - - static v8::Handle get_hasModelChildren(v8::Handle, const v8::AccessorInfo &info) - { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE(data, "Not a valid VisualData object"); - - const QQmlAdaptorModel *const model = static_cast(data)->type->model; - if (data->index >= 0 && *model) { - const QAbstractItemModel * const aim = model->aim(); - return QV4::Value::fromBoolean(aim->hasChildren(aim->index(data->index, 0, model->rootIndex))); - } else { - return QV4::Value::fromBoolean(false); - } + return data; } }; @@ -593,29 +579,36 @@ public: } } - static v8::Handle get_modelData(v8::Handle, const v8::AccessorInfo &info) + static QV4::Value get_modelData(QV4::SimpleCallContext *ctx) { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE(data, "Not a valid VisualData object"); + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); return data->engine->fromVariant(static_cast(data)->cachedData); } - static void set_modelData(v8::Handle, v8::Handle value, const v8::AccessorInfo &info) + static QV4::Value set_modelData(QV4::SimpleCallContext *ctx) { - QQmlDelegateModelItem *data = v8_resource_cast(info.This()); - V8ASSERT_TYPE_SETTER(data, "Not a valid VisualData object"); + QQmlDelegateModelItem *data = v8_resource_cast(ctx->thisObject); + if (!data) + ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + if (!ctx->argumentCount) + ctx->throwTypeError(); + - static_cast(data)->setModelData( - data->engine->toVariant(value->v4Value(), QVariant::Invalid)); + static_cast(data)->setModelData(data->engine->toVariant(ctx->arguments[0], QVariant::Invalid)); } QV4::Value get() { - v8::Handle data = engineData(engine)->constructorListItem.value().asFunctionObject()->newInstance(); - data->SetExternalResource(this); + QQmlAdaptorModelEngineData *data = engineData(engine); + QV4::Object *o = data->v4->newObject(); + o->prototype = data->listItemProto.value().asObject(); + QV4::Value val = QV4::Value::fromObject(o); + v8::Handle(val)->SetExternalResource(this); ++scriptRef; - return data->v4Value(); + return val; } void setValue(const QString &role, const QVariant &value) @@ -961,22 +954,17 @@ void QQmlAdaptorModel::objectDestroyed(QObject *) } QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV8Engine *e) + : v4(QV8Engine::getV4(e)) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(e); - QV4::ArrayObject *a = v4->newArrayObject(); - strings = QV4::Value::fromObject(a); - a->putIndexed(Index, QV4::Value::fromString(v4->newString(QStringLiteral("index")))); - a->putIndexed(ModelData, QV4::Value::fromString(v4->newString(QStringLiteral("modelData")))); - a->putIndexed(HasModelChildren, QV4::Value::fromString(v4->newString(QStringLiteral("hasModelChildren")))); - - v8::Handle listItem = v8::FunctionTemplate::New(); - listItem->InstanceTemplate()->SetHasExternalResource(true); - listItem->InstanceTemplate()->SetAccessor(index(), get_index); - listItem->InstanceTemplate()->SetAccessor( - modelData(), - QQmlDMListAccessorData::get_modelData, - QQmlDMListAccessorData::set_modelData); - constructorListItem = listItem->GetFunction()->v4Value(); + QV4::Object *proto = v4->newObject(); + QV4::Property *p = proto->insertMember(v4->newString(QStringLiteral("index")), + QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id_undefined, get_index)); + p = proto->insertMember(v4->newString(QStringLiteral("modelData")), + QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id_undefined, QQmlDMListAccessorData::get_modelData)); + p->setSetter(v4->newBuiltinFunction(v4->rootContext, v4->id_undefined, QQmlDMListAccessorData::set_modelData)); + listItemProto = QV4::Value::fromObject(proto); } QQmlAdaptorModelEngineData::~QQmlAdaptorModelEngineData() -- 2.7.4