aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-24 14:51:02 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-31 10:50:38 +0100
commit34c85bb56c92316a6ce1c79d25f9653fec14791c (patch)
tree6d3d43de33fa53a1353c52506e989ae126f1361b /src/qml/jsruntime
parentbb7d26ebb0c2e7a9f06a030be8bfcd00e346e06f (diff)
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 <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp63
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp24
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h3
-rw-r--r--src/qml/jsruntime/qv4script.cpp7
-rw-r--r--src/qml/jsruntime/qv4script_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp16
7 files changed, 92 insertions, 29 deletions
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<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex, qmlcontextobject);
- } else if (result->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> 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<QV4::QmlSignalHandler> 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<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *result, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(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<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *result, 0);
+ return vmemo->vmeProperty(property->coreIndex);
+ } else if (property->isDirect()) {
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *result, 0);
+ return LoadProperty<ReadAccessor::Indirect>(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<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ return QObjectWrapper::wrap(ctx->engine, c->getScopeObject());
+}
+
+ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QObjectWrapper> 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<QQmlError> *reportedErrors)
+CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *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<QQmlError> *reportedErrors = 0);
+ static CompiledData::CompilationUnit *precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *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