From 774963f52f569e637f45d6c6079121253e54b61b Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 9 Oct 2013 00:24:55 +0200 Subject: Compile JS functions as part of the QQmlCompiler run in the loader thread ...instead of extracting the function body as a string and compiling it in the GUI thread. Change-Id: I3c3108f6e35464b5581a2d8b5799e7285858ce4d Reviewed-by: Lars Knoll --- src/qml/qml/qqmlcompiler.cpp | 35 ++++++++++++++++------------------- src/qml/qml/qqmlcompiler_p.h | 7 +++++++ src/qml/qml/qqmlobjectcreator.cpp | 5 ++--- src/qml/qml/qqmlscript.cpp | 5 ++--- src/qml/qml/qqmlscript_p.h | 4 ++-- src/qml/qml/qqmlvme.cpp | 3 ++- src/qml/qml/qqmlvmemetaobject.cpp | 30 ++++++++++++++++-------------- src/qml/qml/qqmlvmemetaobject_p.h | 6 +++--- 8 files changed, 50 insertions(+), 45 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index afbec31cb5..d14c790aad 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -811,6 +811,7 @@ bool QQmlCompiler::compile(QQmlEngine *engine, this->unitRoot = root; this->output = out; this->functionsToCompile.clear(); + this->compiledMetaMethods.clear(); // Compile types const QList &resolvedTypes = unit->resolvedTypes(); @@ -955,6 +956,13 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree) } } + foreach (const CompiledMetaMethod &cmm, compiledMetaMethods) { + typedef QQmlVMEMetaData VMD; + VMD *vmd = (QQmlVMEMetaData *)cmm.obj->synthdata.data(); + VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex); + md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex); + } + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Compiler::JSUnitGenerator jsUnitGenerator(&jsModule); QScopedPointer isel(v4->iselFactory->create(v4->executableAllocator, &jsModule, &jsUnitGenerator)); @@ -3234,24 +3242,8 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod // Dynamic slot data - comes after the property data for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - int paramCount = s->parameterNames.count(); - - QString funcScript; - int namesSize = 0; - if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); - funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + - namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); - funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); - for (int jj = 0; jj < paramCount; ++jj) { - if (jj) funcScript.append(QLatin1Char(',')); - funcScript.append(QLatin1String(s->parameterNames.at(jj))); - } - funcScript += QLatin1Char(')') + s->body + QLatin1Char(')'); - - QByteArray utf8 = funcScript.toUtf8(); - VMD::MethodData methodData = { s->parameterNames.count(), - dynamicData.size(), - utf8.length(), + VMD::MethodData methodData = { /*runtimeFunctionIndex*/ 0, // To be filled in later + s->parameterNames.count(), s->location.start.line }; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); @@ -3259,7 +3251,12 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod vmd->methodCount++; md = methodData; - dynamicData.append((const char *)utf8.constData(), utf8.length()); + CompiledMetaMethod cmm; + cmm.obj = obj; + cmm.methodIndex = vmd->methodCount - 1; + functionsToCompile.append(s->funcDecl); + cmm.compiledFunctionIndex = functionsToCompile.count() - 1; + compiledMetaMethods.append(cmm); } if (aliasCount) diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 9ad0b7f0f9..1d1306fba4 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -463,6 +463,13 @@ private: QList functionsToCompile; QList allBindingReferenceRoots; + struct CompiledMetaMethod + { + QQmlScript::Object *obj; + int methodIndex; + int compiledFunctionIndex; // index in functionToCompile + }; + QList compiledMetaMethods; // Compiler component statistics. Only collected if QML_COMPILER_STATS=1 struct ComponentStat diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 42ec886bae..4e70e14894 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -445,9 +445,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) { const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex); - VMD::MethodData methodData = { int(s->nFormals), - /* body offset*/0, - /* body length*/0, + VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### + int(s->nFormals), /* s->location.start.line */0 }; // ### VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index 88603ac2a8..4c1a1f7be5 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -202,7 +202,7 @@ QQmlScript::Object::DynamicSignal::DynamicSignal() } QQmlScript::Object::DynamicSlot::DynamicSlot() -: nextSlot(0), nameIndex(-1) +: funcDecl(0), nextSlot(0), nameIndex(-1) { } @@ -1284,9 +1284,8 @@ bool ProcessAST::visit(AST::UiSourceElement *node) AST::SourceLocation loc = funDecl->rparenToken; loc.offset = loc.end(); loc.startColumn += 1; - QString body = textAt(loc, funDecl->rbraceToken); slot->name = funDecl->name; - slot->body = body; + slot->funcDecl = funDecl; obj->dynamicSlots.append(slot); } else { diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index f8786b0a2d..7aecba993b 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE class QByteArray; class QQmlPropertyCache; -namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; } } +namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; class FunctionDeclaration; } } namespace QQmlCompilerTypes { struct BindingReference; struct ComponentCompileState; } namespace QQmlScript { @@ -433,8 +433,8 @@ public: { DynamicSlot(); + QQmlJS::AST::FunctionDeclaration *funcDecl; QHashedStringRef name; - QString body; QList parameterNames; LocationSpan location; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index c5dfeb2956..21f7ce4cab 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -714,7 +714,8 @@ QObject *QQmlVME::run(QList *errors, const QQmlVMEMetaData *data = (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData(); - (void)new QQmlVMEMetaObject(target, propertyCache, data); + QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, target, objects.count() - 1); + (void)new QQmlVMEMetaObject(target, propertyCache, data, qmlContext, COMP); QQmlData *ddata = QQmlData::get(target, true); if (ddata->propertyCache) ddata->propertyCache->release(); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 7c033acf47..915314e322 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -559,7 +559,7 @@ QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o) QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, - const QQmlVMEMetaData *meta) + const QQmlVMEMetaData *meta, QV4::ExecutionContext *qmlBindingContext, QQmlCompiledData *compiledData) : object(obj), ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta), hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1), @@ -603,6 +603,21 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (needsJSWrapper) ensureQObjectWrapper(); + + if (qmlBindingContext && metaData->methodCount) { + v8methods = new QV4::PersistentValue[metaData->methodCount]; + + QV4::CompiledData::CompilationUnit *compilationUnit = compiledData->compilationUnit; + QV4::Scope scope(QQmlEnginePrivate::get(ctxt->engine)->v4engine()); + QV4::ScopedObject o(scope); + for (int index = 0; index < metaData->methodCount; ++index) { + QQmlVMEMetaData::MethodData *data = metaData->methodData() + index; + + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex]; + o = QV4::FunctionObject::creatScriptFunction(qmlBindingContext, runtimeFunction); + v8methods[index] = o; + } + } } QQmlVMEMetaObject::~QQmlVMEMetaObject() @@ -974,19 +989,6 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) if (!v8methods) v8methods = new QV4::PersistentValue[metaData->methodCount]; - if (v8methods[index].isUndefined()) { - QQmlVMEMetaData::MethodData *data = metaData->methodData() + index; - - const char *body = ((const char*)metaData) + data->bodyOffset; - int bodyLength = data->bodyLength; - - // XXX We should evaluate all methods in a single big script block to - // improve the call time between dynamic methods defined on the same - // object - v8methods[index] = QQmlExpressionPrivate::evalFunction(ctxt, object, QString::fromUtf8(body, bodyLength), - ctxt->urlString, data->lineNumber); - } - return v8methods[index].value(); } diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 056139114c..25a577d2e6 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -119,9 +119,8 @@ struct QQmlVMEMetaData }; struct MethodData { + int runtimeFunctionIndex; int parameterCount; - int bodyOffset; - int bodyLength; quint16 lineNumber; }; @@ -159,7 +158,8 @@ class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data); + QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data, + QV4::ExecutionContext *qmlBindingContext = 0, QQmlCompiledData *compiledData = 0); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; -- cgit v1.2.3