From 34c85bb56c92316a6ce1c79d25f9653fec14791c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 24 Oct 2013 14:51:02 +0200 Subject: Initial support for resolving meta-property access for the scope and context objects at QML compile time This avoids having to do a string lookup for ids and in the import cache at run-time, before we can do a string hash lookup in the property cache. Instead we resolve final properties in the context and scope object at compile time and look them up at run-time using their index instead. The dependencies to these properties are also tracked separately and recorded in the compiled data. This is merely the initial patch. There's a lot left to do, such as having specialized getter and setters for specific property types. Setters are missing altogether right now and will fall back to name lookup. Change-Id: If3cb4e7c9454ef4850a615f0935b311c9395b165 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 63 ++++++++++++++++++++++----------- src/qml/jsruntime/qv4qobjectwrapper_p.h | 4 +++ src/qml/jsruntime/qv4runtime.cpp | 24 +++++++++++++ src/qml/jsruntime/qv4runtime_p.h | 3 ++ src/qml/jsruntime/qv4script.cpp | 7 ++-- src/qml/jsruntime/qv4script_p.h | 4 +-- src/qml/jsruntime/qv4vme_moth.cpp | 16 +++++++-- 7 files changed, 92 insertions(+), 29 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index a4bfc93c36..22e2019112 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -329,16 +329,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD if (hasProperty) *hasProperty = true; - if (result->isFunction() && !result->isVarProperty()) { - if (result->isVMEFunction()) { + return getProperty(ctx, result); +} + +ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property) +{ + QV4::Scope scope(ctx); + + if (property->isFunction() && !property->isVarProperty()) { + if (property->isVMEFunction()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object); Q_ASSERT(vmemo); - return vmemo->vmeMethod(result->coreIndex); - } else if (result->isV4Function()) { + return vmemo->vmeMethod(property->coreIndex); + } else if (property->isV4Function()) { QV4::Scoped qmlcontextobject(scope, ctx->engine->qmlContextObject()); - return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex, qmlcontextobject); - } else if (result->isSignalHandler()) { - QV4::Scoped handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, result->coreIndex)); + return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject); + } else if (property->isSignalHandler()) { + QV4::Scoped handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex)); QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect"))); QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect"))); @@ -347,45 +354,46 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD return handler.asReturnedValue(); } else { - return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex); + return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex); } } QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0; - if (result->hasAccessors()) { + if (property->hasAccessors()) { QQmlNotifier *n = 0; QQmlNotifier **nptr = 0; - if (ep && ep->propertyCapture && result->accessors->notifier) + if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty(ctx->engine->v8Engine, m_object, *result, nptr)); + QV4::ScopedValue rv(scope, LoadProperty(ctx->engine->v8Engine, m_object, *property, nptr)); - if (result->accessors->notifier) { + if (property->accessors->notifier) { if (n) ep->captureProperty(n); } else { - ep->captureProperty(m_object, result->coreIndex, result->notifyIndex); + ep->captureProperty(m_object, property->coreIndex, property->notifyIndex); } return rv.asReturnedValue(); } - if (ep && !result->isConstant()) - ep->captureProperty(m_object, result->coreIndex, result->notifyIndex); + if (ep && !property->isConstant()) + ep->captureProperty(m_object, property->coreIndex, property->notifyIndex); - if (result->isVarProperty()) { + if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object); Q_ASSERT(vmemo); - return vmemo->vmeProperty(result->coreIndex); - } else if (result->isDirect()) { - return LoadProperty(ctx->engine->v8Engine, m_object, *result, 0); + return vmemo->vmeProperty(property->coreIndex); + } else if (property->isDirect()) { + return LoadProperty(ctx->engine->v8Engine, m_object, *property, 0); } else { - return LoadProperty(ctx->engine->v8Engine, m_object, *result, 0); + return LoadProperty(ctx->engine->v8Engine, m_object, *property, 0); } } + ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) { QV4::Scope scope(ctx); @@ -603,6 +611,21 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) } } +ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex) +{ + if (QQmlData::wasDeleted(m_object)) + return QV4::Encode::null(); + QQmlData *ddata = QQmlData::get(m_object, /*create*/false); + if (!ddata) + return QV4::Encode::undefined(); + + QQmlPropertyCache *cache = ddata->propertyCache; + Q_ASSERT(cache); + QQmlPropertyData *property = cache->property(propertyIndex); + Q_ASSERT(property); // We resolved this property earlier, so it better exist! + return getProperty(ctx, property); +} + ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object) { QQmlEngine *qmlEngine = engine->v8Engine->engine(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index eadbacc096..6f886f0522 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -94,7 +94,11 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object using Object::get; + ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex); + private: + ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property); + static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object); QObjectWrapper(ExecutionEngine *engine, QObject *object); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 0f23520610..aa8ab1c172 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1183,6 +1183,30 @@ ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id) return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data()); } +ReturnedValue __qmljs_get_context_object(ExecutionContext *ctx) +{ + QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine); + return QObjectWrapper::wrap(ctx->engine, context->contextObject); +} + +ReturnedValue __qmljs_get_scope_object(ExecutionContext *ctx) +{ + Scope scope(ctx); + QV4::Scoped c(scope, ctx->engine->qmlContextObject()->getPointer()->as()); + return QObjectWrapper::wrap(ctx->engine, c->getScopeObject()); +} + +ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex) +{ + Scope scope(ctx); + QV4::Scoped wrapper(scope, object); + if (!wrapper) { + ctx->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); + } + return wrapper->getProperty(ctx, propertyIndex); +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index e04baadf53..464595a380 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -165,6 +165,9 @@ QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::Va void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value); QV4::ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id); +QV4::ReturnedValue __qmljs_get_context_object(ExecutionContext *ctx); +QV4::ReturnedValue __qmljs_get_scope_object(ExecutionContext *ctx); +QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex); // For each QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 6e2c26edaf..f1903cf323 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -207,8 +207,7 @@ void Script::parse() inheritedLocals.append(*i ? (*i)->toQString() : QString()); RuntimeCodegen cg(scope, strictMode); - cg.generateFromProgram(sourceFile, sourceCode, program, &module, - parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals); + cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals); if (v4->hasException) return; @@ -286,7 +285,7 @@ Function *Script::function() return vmFunction; } -CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, bool parseAsBinding, QList *reportedErrors) +CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList *reportedErrors) { using namespace QQmlJS; using namespace QQmlJS::AST; @@ -330,7 +329,7 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const } QQmlJS::Codegen cg(/*strict mode*/false); - cg.generateFromProgram(url.toString(), source, program, &module, parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::GlobalCode); + cg.generateFromProgram(url.toString(), source, program, &module, QQmlJS::Codegen::EvalCode); errors = cg.errors(); if (!errors.isEmpty()) { if (reportedErrors) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 52ad4dd78c..657923062b 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -100,9 +100,7 @@ struct Q_QML_EXPORT Script { Function *function(); - static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, - bool parseAsBinding, - QList *reportedErrors = 0); + static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList *reportedErrors = 0); static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject); }; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 5a7b33a5d5..1797f0b2ee 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -305,6 +305,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) + MOTH_BEGIN_INSTR(LoadQObjectProperty) + STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex)); + MOTH_END_INSTR(LoadQObjectProperty) + MOTH_BEGIN_INSTR(Push) TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; @@ -628,9 +632,17 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, VALUE(instr.result) = context->callData->thisObject; MOTH_END_INSTR(LoadThis) - MOTH_BEGIN_INSTR(LoadIdObject) + MOTH_BEGIN_INSTR(LoadQmlIdObject) VALUE(instr.result) = __qmljs_get_id_object(context, instr.id); - MOTH_END_INSTR(LoadIdObject) + MOTH_END_INSTR(LoadQmlIdObject) + + MOTH_BEGIN_INSTR(LoadQmlContextObject) + VALUE(instr.result) = __qmljs_get_context_object(context); + MOTH_END_INSTR(LoadContextObject) + + MOTH_BEGIN_INSTR(LoadQmlScopeObject) + VALUE(instr.result) = __qmljs_get_scope_object(context); + MOTH_END_INSTR(LoadScopeObject) #ifdef MOTH_THREADED_INTERPRETER // nothing to do -- cgit v1.2.3