From 69a17a912a41458a2b4a20bdbda1717920275250 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 17 Jun 2011 11:37:17 +1000 Subject: Evaluate all shared bindings together using a shared context The vast majority of bindings are capable of being shared (that is, don't introduce closures themselves) and consequently this improves the performance of almost every app. --- src/declarative/qml/qdeclarativebinding.cpp | 33 +-- src/declarative/qml/qdeclarativebinding_p.h | 4 +- src/declarative/qml/qdeclarativebinding_p_p.h | 1 + src/declarative/qml/qdeclarativecompileddata.cpp | 2 + src/declarative/qml/qdeclarativecompiler.cpp | 162 +++++++++------ src/declarative/qml/qdeclarativecompiler_p.h | 11 +- src/declarative/qml/qdeclarativecontext.cpp | 16 +- src/declarative/qml/qdeclarativecontext_p.h | 8 +- src/declarative/qml/qdeclarativeexpression.cpp | 50 ++--- src/declarative/qml/qdeclarativeexpression.h | 4 +- src/declarative/qml/qdeclarativeexpression_p.h | 2 +- src/declarative/qml/qdeclarativeinstruction.cpp | 8 +- src/declarative/qml/qdeclarativeinstruction_p.h | 10 +- src/declarative/qml/qdeclarativerefcount_p.h | 67 ++++++ src/declarative/qml/qdeclarativevme.cpp | 44 +++- src/declarative/qml/v4/qdeclarativev4bindings.cpp | 1 + src/declarative/qml/v8/qv8bindings.cpp | 235 ++++++++++++++++++++++ src/declarative/qml/v8/qv8bindings_p.h | 94 +++++++++ src/declarative/qml/v8/v8.pri | 2 + 19 files changed, 623 insertions(+), 131 deletions(-) create mode 100644 src/declarative/qml/v8/qv8bindings.cpp create mode 100644 src/declarative/qml/v8/qv8bindings_p.h (limited to 'src') diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index d1fdec5a63..fee55545cf 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -226,15 +226,6 @@ QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate() { } -QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj, - QDeclarativeContextData *ctxt, const QString &url, int lineNumber, - QObject *parent) -: QDeclarativeExpression(ctxt, data, rc, obj, url, lineNumber, *new QDeclarativeBindingPrivate) -{ - setParent(parent); - setNotifyOnValueChanged(true); -} - QDeclarativeBinding * QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt, const QString &url, int lineNumber, QObject *parent) @@ -251,7 +242,7 @@ QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeCont typeData = engine->typeLoader.get(ctxtdata->url); cdata = typeData->compiledData(); } - QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0; + QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, parent) : 0; if (typeData) typeData->release(); return rv; @@ -273,6 +264,15 @@ QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDecl setNotifyOnValueChanged(true); } +QDeclarativeBinding::QDeclarativeBinding(const QString &str, bool isRewritten, QObject *obj, + QDeclarativeContextData *ctxt, + const QString &url, int lineNumber, QObject *parent) +: QDeclarativeExpression(ctxt, obj, str, isRewritten, url, lineNumber, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + /*! \internal @@ -413,19 +413,17 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) } else { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine); - ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. + ep->referenceScarceResources(); bool isUndefined = false; - QVariant value; v8::HandleScope handle_scope; v8::Context::Scope scope(ep->v8engine.context()); v8::Local result = d->v8value(0, &isUndefined); bool needsErrorData = false; - if (!watcher.wasDeleted() && !d->error.isValid()) { + if (!watcher.wasDeleted() && !d->error.isValid()) needsErrorData = !d->writeBindingResult(d, d->property, result, isUndefined, flags); - } if (!watcher.wasDeleted()) { @@ -453,10 +451,15 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) if (!watcher.wasDeleted()) d->updating = false; } else { - qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name()); + QDeclarativeBindingPrivate::printBindingLoopError(d->property); } } +void QDeclarativeBindingPrivate::printBindingLoopError(QDeclarativeProperty &prop) +{ + qmlInfo(prop.object()) << QDeclarativeBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name()); +} + void QDeclarativeBindingPrivate::emitValueChanged() { Q_Q(QDeclarativeBinding); diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index e646c86df3..fedd63634b 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -152,8 +152,8 @@ public: QDeclarativeBinding(const QString &, QObject *, QDeclarativeContext *, QObject *parent=0); QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0); - QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *, - const QString &, int, QObject *parent); + QDeclarativeBinding(const QString &, bool isRewritten, QObject *, QDeclarativeContextData *, + const QString &url, int lineNumber, QObject *parent=0); QDeclarativeBinding(void *, QObject *, QDeclarativeContextData *, QObject *parent=0); void setTarget(const QDeclarativeProperty &); diff --git a/src/declarative/qml/qdeclarativebinding_p_p.h b/src/declarative/qml/qdeclarativebinding_p_p.h index 1b1b03b228..6caf13635f 100644 --- a/src/declarative/qml/qdeclarativebinding_p_p.h +++ b/src/declarative/qml/qdeclarativebinding_p_p.h @@ -72,6 +72,7 @@ public: static bool writeBindingResult(QDeclarativeJavaScriptExpression *expression, QDeclarativeProperty &prop, v8::Handle value, bool isUndefined, QDeclarativePropertyPrivate::WriteFlags flags); + static void printBindingLoopError(QDeclarativeProperty &prop); protected: virtual void refresh(); diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp index 2ea41d857f..fc4b28b666 100644 --- a/src/declarative/qml/qdeclarativecompileddata.cpp +++ b/src/declarative/qml/qdeclarativecompileddata.cpp @@ -128,6 +128,8 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData() qDeleteAll(cachedPrograms); qDeleteAll(cachedClosures); + + qPersistentDispose(v8bindings); } void QDeclarativeCompiledData::clear() diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index e4ad463dad..a0a6680d2e 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -708,6 +708,14 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree) init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); output->addInstruction(init); + if (!compileState.v8BindingProgram.isEmpty()) { + QDeclarativeInstruction bindings; + bindings.setType(QDeclarativeInstruction::InitV8Bindings); + bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram); + bindings.initV8Bindings.line = compileState.v8BindingProgramLine; + output->addInstruction(bindings); + } + genObject(tree); QDeclarativeInstruction def; @@ -1208,6 +1216,14 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); output->addInstruction(init); + if (!compileState.v8BindingProgram.isEmpty()) { + QDeclarativeInstruction bindings; + bindings.setType(QDeclarativeInstruction::InitV8Bindings); + bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram); + bindings.initV8Bindings.line = compileState.v8BindingProgramLine; + output->addInstruction(bindings); + } + genObject(root); QDeclarativeInstruction def; @@ -2311,33 +2327,15 @@ const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) con } // similar to logic of completeComponentBuild, but also sticks data -// into datas at the end +// into primitives at the end int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) { QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1)); - bool isSharable = false; - QString rewrite = rewriteBinding(expression, 0, &isSharable); - - quint32 length = rewrite.length(); - quint32 pc; - - if (isSharable) { - pc = output->cachedClosures.count(); - pc |= 0x80000000; - output->cachedClosures.append(0); - } else { - pc = output->cachedPrograms.length(); - output->cachedPrograms.append(0); - } - QByteArray compiledData = - QByteArray((const char *)&pc, sizeof(quint32)) + - QByteArray((const char *)&length, sizeof(quint32)) + - QByteArray((const char *)rewrite.constData(), - rewrite.length() * sizeof(QChar)); + QString rewrite = rewriteBinding(expression, 0, 0); - return output->indexForByteArray(compiledData); + return output->indexForString(rewrite); } // Ensures that the dynamic meta specification on obj is valid @@ -2841,9 +2839,9 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *bindi Q_ASSERT(compileState.bindings.contains(binding)); const BindingReference &ref = compileState.bindings.value(binding); - if (ref.dataType == BindingReference::Experimental) { + if (ref.dataType == BindingReference::V4) { QDeclarativeInstruction store; - store.setType(QDeclarativeInstruction::StoreCompiledBinding); + store.setType(QDeclarativeInstruction::StoreV4Binding); store.assignBinding.value = ref.compiledIndex; store.assignBinding.context = ref.bindingContext.stack; store.assignBinding.owner = ref.bindingContext.owner; @@ -2855,28 +2853,43 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *bindi store.assignBinding.property = prop->index; store.assignBinding.line = binding->location.start.line; output->addInstruction(store); - return; - } + } else if (ref.dataType == BindingReference::V8) { + QDeclarativeInstruction store; + store.setType(QDeclarativeInstruction::StoreV8Binding); + store.assignBinding.value = ref.compiledIndex; + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + store.assignBinding.line = binding->location.start.line; - QDeclarativeInstruction store; - if (!prop->isAlias) - store.setType(QDeclarativeInstruction::StoreBinding); - else - store.setType(QDeclarativeInstruction::StoreBindingOnAlias); - store.assignBinding.value = output->indexForByteArray(ref.compiledData); - store.assignBinding.context = ref.bindingContext.stack; - store.assignBinding.owner = ref.bindingContext.owner; - store.assignBinding.line = binding->location.start.line; - - Q_ASSERT(ref.bindingContext.owner == 0 || - (ref.bindingContext.owner != 0 && valueTypeProperty)); - if (ref.bindingContext.owner) { - store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + Q_ASSERT(ref.bindingContext.owner == 0 || + (ref.bindingContext.owner != 0 && valueTypeProperty)); + if (ref.bindingContext.owner) { + store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.assignBinding.property = genPropertyData(prop); + } + + output->addInstruction(store); } else { - store.assignBinding.property = genPropertyData(prop); - } + QDeclarativeInstruction store; + if (!prop->isAlias) + store.setType(QDeclarativeInstruction::StoreBinding); + else + store.setType(QDeclarativeInstruction::StoreBindingOnAlias); + store.assignBinding.value = output->indexForString(ref.rewrittenExpression); + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + store.assignBinding.line = binding->location.start.line; - output->addInstruction(store); + Q_ASSERT(ref.bindingContext.owner == 0 || + (ref.bindingContext.owner != 0 && valueTypeProperty)); + if (ref.bindingContext.owner) { + store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.assignBinding.property = genPropertyData(prop); + } + output->addInstruction(store); + } } int QDeclarativeCompiler::genContextCache() @@ -2929,6 +2942,8 @@ bool QDeclarativeCompiler::completeComponentBuild() QDeclarativeV4Compiler bindingCompiler; + QList sharedBindings; + for (QHash::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { @@ -2943,44 +2958,67 @@ bool QDeclarativeCompiler::completeComponentBuild() int index = bindingCompiler.compile(expr, enginePrivate); if (index != -1) { - binding.dataType = BindingReference::Experimental; + binding.dataType = BindingReference::V4; binding.compiledIndex = index; componentStat.optimizedBindings.append(iter.key()->location); continue; } } - binding.dataType = BindingReference::QtScript; - // Pre-rewrite the expression QString expression = binding.expression.asScript(); QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName('$'+binding.property->name); bool isSharable = false; - expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); - - quint32 length = expression.length(); - quint32 pc; - - if (isSharable) { - pc = output->cachedClosures.count(); - pc |= 0x80000000; - output->cachedClosures.append(0); + binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); + + if (isSharable && !binding.property->isAlias /* See above re alias */ && + binding.property->type != qMetaTypeId()) { + binding.dataType = BindingReference::V8; + sharedBindings.append(&iter.value()); } else { - pc = output->cachedPrograms.length(); - output->cachedPrograms.append(0); + binding.dataType = BindingReference::QtScript; } - binding.compiledData = - QByteArray((const char *)&pc, sizeof(quint32)) + - QByteArray((const char *)&length, sizeof(quint32)) + - QByteArray((const char *)expression.constData(), - expression.length() * sizeof(QChar)); - componentStat.scriptBindings.append(iter.key()->location); } + if (!sharedBindings.isEmpty()) { + struct Sort { + static bool lt(const BindingReference *lhs, const BindingReference *rhs) + { + return lhs->value->location.start.line < rhs->value->location.start.line; + } + }; + + qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt); + + int startLineNumber = sharedBindings.at(0)->value->location.start.line; + int lineNumber = startLineNumber; + + QString functionArray(QLatin1String("[")); + for (int ii = 0; ii < sharedBindings.count(); ++ii) { + BindingReference *reference = sharedBindings.at(ii); + QDeclarativeParser::Value *value = reference->value; + const QString &expression = reference->rewrittenExpression; + + if (ii != 0) functionArray += QLatin1String(","); + + while (lineNumber < value->location.start.line) { + lineNumber++; + functionArray += QLatin1String("\n"); + } + + functionArray += expression; + reference->compiledIndex = ii; + } + functionArray += QLatin1String("]"); + + compileState.v8BindingProgram = functionArray; + compileState.v8BindingProgramLine = startLineNumber; + } + if (bindingCompiler.isValid()) compileState.compiledBindingData = bindingCompiler.program(); diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index e4b9240a93..2756c3fefb 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -55,6 +55,7 @@ #include "qdeclarative.h" #include "qdeclarativeerror.h" +#include "private/qv8_p.h" #include "private/qdeclarativeinstruction_p.h" #include "private/qdeclarativeparser_p.h" #include "private/qdeclarativeengine_p.h" @@ -103,6 +104,8 @@ public: }; QList types; + v8::Persistent v8bindings; + const QMetaObject *root; QAbstractDynamicMetaObject rootData; QDeclarativePropertyCache *rootPropertyCache; @@ -283,12 +286,12 @@ private: QDeclarativeParser::Property *property; QDeclarativeParser::Value *value; - enum DataType { QtScript, Experimental }; + enum DataType { QtScript, V4, V8 }; DataType dataType; int compiledIndex; - QByteArray compiledData; + QString rewrittenExpression; BindingContext bindingContext; }; void addBindingReference(const BindingReference &); @@ -296,7 +299,7 @@ private: struct ComponentCompileState { ComponentCompileState() - : parserStatusCount(0), pushedProperties(0), nested(false), root(0) {} + : parserStatusCount(0), pushedProperties(0), nested(false), v8BindingProgramLine(-1), root(0) {} QHash ids; QHash idIndexes; int parserStatusCount; @@ -304,6 +307,8 @@ private: bool nested; QByteArray compiledBindingData; + QString v8BindingProgram; + int v8BindingProgramLine; QHash bindings; QHash signalExpressions; diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index c2c21d30fb..caa3b0c7d8 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -48,6 +48,7 @@ #include "qdeclarativeengine.h" #include "qdeclarativeinfo.h" #include "private/qdeclarativev4bindings_p.h" +#include "private/qv8bindings_p.h" #include #include @@ -499,16 +500,16 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListPropertyrelease(); - if (optimizedBindings) - optimizedBindings->release(); + if (v4bindings) + v4bindings->release(); + + if (v8bindings) + v8bindings->release(); for (int ii = 0; ii < importedScripts.count(); ++ii) { qPersistentDispose(importedScripts[ii]); diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index ac933a3ae3..59d886c366 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE +class QV8Bindings; class QDeclarativeContext; class QDeclarativeExpression; class QDeclarativeEngine; @@ -192,9 +193,6 @@ public: void setIdProperty(int, QObject *); void setIdPropertyData(QDeclarativeIntegerCache *); - // Optimized binding pointer - QDeclarativeV4Bindings *optimizedBindings; - // Linked contexts. this owns linkedContext. QDeclarativeContextData *linkedContext; @@ -202,6 +200,10 @@ public: // context QDeclarativeComponentAttached *componentAttached; + // Optimized binding objects. Needed for deferred properties. + QDeclarativeV4Bindings *v4bindings; + QV8Bindings *v8bindings; + // Return the outermost id for obj, if any. QString findObjectId(const QObject *obj) const; diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index d709d5ce26..27bd8f8147 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -113,32 +113,20 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Hand extractExpressionFromFunction = true; } -void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, - QDeclarativeRefCount *rc, +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, bool isRewritten, QObject *me, const QString &srcUrl, int lineNumber) { url = srcUrl; line = lineNumber; - Q_ASSERT(!dataRef); - - dataRef = rc; - if (dataRef) dataRef->addref(); - - quint32 *exprData = (quint32 *)expr; - QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc; - - expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); - - int progIdx = *(exprData); - bool isSharedProgram = progIdx & 0x80000000; - progIdx &= 0x7FFFFFFF; - - v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope); - - setUseSharedContext(false); + expression = expr; - expressionFunctionValid = true; + if (!isRewritten) { + expressionFunctionValid = false; + } else { + v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope); + expressionFunctionValid = true; + } QDeclarativeAbstractExpression::setContext(ctxt); setScopeObject(me); @@ -214,14 +202,14 @@ QDeclarativeExpression::QDeclarativeExpression() } /*! \internal */ -QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr, - QDeclarativeRefCount *rc, QObject *me, - const QString &url, int lineNumber, +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, + QObject *object, const QString &expr, bool isRewritten, + const QString &url, int lineNumber, QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QDeclarativeExpression); - d->init(ctxt, expr, rc, me, url, lineNumber); + d->init(ctxt, expr, isRewritten, object, url, lineNumber); if (QDeclarativeExpression_notifyIdx == -1) QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); @@ -263,7 +251,7 @@ QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &s } if (cdata) - d->init(ctxtdata, (void*)cdata->datas.at(id).constData(), cdata, script.scopeObject(), + d->init(ctxtdata, cdata->primitives.at(id), cdata, script.scopeObject(), cdata->name, script.d.data()->lineNumber); else defaultConstruction = true; @@ -338,7 +326,7 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO new QDeclarativeExpression(ctxt, scope, &function, ...); */ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr, - QDeclarativeExpressionPrivate &dd) + QDeclarativeExpressionPrivate &dd) : QObject(dd, 0) { v8::Handle function = *(v8::Handle *)functionPtr; @@ -476,7 +464,9 @@ v8::Local QDeclarativeJavaScriptExpression::evaluate(v8::HandlecaptureProperties; QPODVector lastCapturedProperties; ep->captureProperties = notifyOnValueChanged(); - ep->capturedProperties.copyAndClear(lastCapturedProperties); + + if (ep->capturedProperties.count()) + ep->capturedProperties.copyAndClear(lastCapturedProperties); QDeclarativeContextData *lastSharedContext = 0; QObject *lastSharedScope = 0; @@ -532,7 +522,11 @@ v8::Local QDeclarativeJavaScriptExpression::evaluate(v8::HandlecapturedProperties); } - lastCapturedProperties.copyAndClear(ep->capturedProperties); + if (lastCapturedProperties.count()) + lastCapturedProperties.copyAndClear(ep->capturedProperties); + else + ep->capturedProperties.clear(); + ep->captureProperties = lastCaptureProperties; return result; diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h index 217545e08e..edd93a1240 100644 --- a/src/declarative/qml/qdeclarativeexpression.h +++ b/src/declarative/qml/qdeclarativeexpression.h @@ -98,8 +98,8 @@ protected: QDeclarativeExpressionPrivate &dd); QDeclarativeExpression(QDeclarativeContextData *, QObject *, void *, QDeclarativeExpressionPrivate &dd); - QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc, - QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd); + QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &, bool, + const QString &, int, QDeclarativeExpressionPrivate &dd); private: QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &); diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index dcf47c3134..2a26c26700 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -193,7 +193,7 @@ public: void init(QDeclarativeContextData *, const QString &, QObject *); void init(QDeclarativeContextData *, v8::Handle, QObject *); - void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int); + void init(QDeclarativeContextData *, const QString &, bool, QObject *, const QString &, int); QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index 79a2a1cc34..4f64e4e2ba 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -168,15 +168,21 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) case QDeclarativeInstruction::AssignCustomType: qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type; break; + case QDeclarativeInstruction::InitV8Bindings: + qWarning().nospace() << idx << "\t\t" << "INIT_V8_BINDING\t" << instr->initV8Bindings.program << "\t" << instr->initV8Bindings.line; + break; case QDeclarativeInstruction::StoreBinding: qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; break; case QDeclarativeInstruction::StoreBindingOnAlias: qWarning().nospace() << idx << "\t\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; break; - case QDeclarativeInstruction::StoreCompiledBinding: + case QDeclarativeInstruction::StoreV4Binding: qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; break; + case QDeclarativeInstruction::StoreV8Binding: + qWarning().nospace() << idx << "\t\t" << "STORE_V8_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; case QDeclarativeInstruction::StoreValueSource: qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; break; diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index 3db55a66d3..5c51ea8d5f 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -95,9 +95,11 @@ QT_BEGIN_NAMESPACE F(StoreImportedScript, storeScript) \ F(StoreScriptString, storeScriptString) \ F(BeginObject, begin) \ + F(InitV8Bindings, initV8Bindings) \ F(StoreBinding, assignBinding) \ F(StoreBindingOnAlias, assignBinding) \ - F(StoreCompiledBinding, assignBinding) \ + F(StoreV4Binding, assignBinding) \ + F(StoreV8Binding, assignBinding) \ F(StoreValueSource, assignValueSource) \ F(StoreValueInterceptor, assignValueInterceptor) \ F(StoreObjectQList, common) \ @@ -182,6 +184,11 @@ union QDeclarativeInstruction int owner; int castValue; }; + struct instr_initV8Bindings { + QML_INSTR_HEADER + int program; + int line; + }; struct instr_assignBinding { QML_INSTR_HEADER unsigned int property; @@ -411,6 +418,7 @@ union QDeclarativeInstruction instr_setId setId; instr_assignValueSource assignValueSource; instr_assignValueInterceptor assignValueInterceptor; + instr_initV8Bindings initV8Bindings; instr_assignBinding assignBinding; instr_fetch fetch; instr_fetchValue fetchValue; diff --git a/src/declarative/qml/qdeclarativerefcount_p.h b/src/declarative/qml/qdeclarativerefcount_p.h index 3bbb7b0ff3..381327098c 100644 --- a/src/declarative/qml/qdeclarativerefcount_p.h +++ b/src/declarative/qml/qdeclarativerefcount_p.h @@ -73,6 +73,73 @@ private: int refCount; }; +template +class QDeclarativeRefPointer +{ +public: + inline QDeclarativeRefPointer(); + inline QDeclarativeRefPointer(T *); + inline QDeclarativeRefPointer(const QDeclarativeRefPointer &); + inline ~QDeclarativeRefPointer(); + + inline QDeclarativeRefPointer &operator=(const QDeclarativeRefPointer &o); + inline QDeclarativeRefPointer &operator=(T *); + + inline bool isNull() const { return !o; } + + inline T* operator->() const { return o; } + inline T& operator*() const { return *o; } + inline operator T*() const { return o; } + inline T* data() const { return o; } + +private: + T *o; +}; + +template +QDeclarativeRefPointer::QDeclarativeRefPointer() +: o(0) +{ +} + +template +QDeclarativeRefPointer::QDeclarativeRefPointer(T *o) +: o(o) +{ + if (o) o->addref(); +} + +template +QDeclarativeRefPointer::QDeclarativeRefPointer(const QDeclarativeRefPointer &other) +: o(other.o) +{ + if (o) o->addref(); +} + +template +QDeclarativeRefPointer::~QDeclarativeRefPointer() +{ + if (o) o->release(); +} + +template +QDeclarativeRefPointer &QDeclarativeRefPointer::operator=(const QDeclarativeRefPointer &other) +{ + if (other.o) other.o->addref(); + if (o) o->release(); + o = other.o; + return *this; +} + +template +QDeclarativeRefPointer &QDeclarativeRefPointer::operator=(T *other) +{ + if (other) other->addref(); + if (o) o->release(); + o = other; + return *this; +} + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 4d5fa3607c..377ef9db16 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -58,6 +58,7 @@ #include "private/qdeclarativebinding_p_p.h" #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativev4bindings_p.h" +#include "private/qv8bindings_p.h" #include "private/qdeclarativeglobal_p.h" #include "qdeclarativescriptstring.h" #include "qdeclarativescriptstring_p.h" @@ -191,8 +192,10 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, parserStatus = QDeclarativeEnginePrivate::SimpleList(instr.parserStatusSize); if (instr.contextCache != -1) ctxt->setIdPropertyData(comp->contextCaches.at(instr.contextCache)); - if (instr.compiledBinding != -1) - ctxt->optimizedBindings = new QDeclarativeV4Bindings(datas.at(instr.compiledBinding).constData(), ctxt); + if (instr.compiledBinding != -1) { + const char *v4data = datas.at(instr.compiledBinding).constData(); + ctxt->v4bindings = new QDeclarativeV4Bindings(v4data, ctxt); + } QML_END_INSTR(Init) QML_BEGIN_INSTR(Done) @@ -657,6 +660,10 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, status->classBegin(); QML_END_INSTR(BeginObject) + QML_BEGIN_INSTR(InitV8Bindings) + ctxt->v8bindings = new QV8Bindings(primitives.at(instr.program), instr.line, comp, ctxt); + QML_END_INSTR(InitV8Bindings) + QML_BEGIN_INSTR(StoreBinding) QObject *target = stack.at(stack.count() - 1 - instr.owner); @@ -671,7 +678,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex)) break; - QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.value).constData(), comp, context, ctxt, comp->name, instr.line, 0); + QDeclarativeBinding *bind = new QDeclarativeBinding(primitives.at(instr.value), true, + context, ctxt, comp->name, instr.line); bindValues.append(bind); bind->m_mePtr = &bindValues.values[bindValues.count - 1]; bind->setTarget(mp); @@ -693,7 +701,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex)) break; - QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.value).constData(), comp, context, ctxt, comp->name, instr.line, 0); + QDeclarativeBinding *bind = new QDeclarativeBinding(primitives.at(instr.value), true, + context, ctxt, comp->name, instr.line); bindValues.append(bind); bind->m_mePtr = &bindValues.values[bindValues.count - 1]; bind->setTarget(mp); @@ -702,7 +711,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, if (old) { old->destroy(); } QML_END_INSTR(StoreBindingOnAlias) - QML_BEGIN_INSTR(StoreCompiledBinding) + QML_BEGIN_INSTR(StoreV4Binding) QObject *target = stack.at(stack.count() - 1 - instr.owner); QObject *scope = @@ -713,11 +722,32 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, break; QDeclarativeAbstractBinding *binding = - ctxt->optimizedBindings->configBinding(instr.value, target, scope, property); + ctxt->v4bindings->configBinding(instr.value, target, scope, property); bindValues.append(binding); binding->m_mePtr = &bindValues.values[bindValues.count - 1]; binding->addToObject(target, property); - QML_END_INSTR(StoreCompiledBinding) + QML_END_INSTR(StoreV4Binding) + + QML_BEGIN_INSTR(StoreV8Binding) + QObject *target = + stack.at(stack.count() - 1 - instr.owner); + QObject *scope = + stack.at(stack.count() - 1 - instr.context); + + QDeclarativeProperty mp = + QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt); + + int coreIndex = mp.index(); + + if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex)) + break; + + QDeclarativeAbstractBinding *binding = + ctxt->v8bindings->configBinding(instr.value, target, scope, mp, instr.line); + bindValues.append(binding); + binding->m_mePtr = &bindValues.values[bindValues.count - 1]; + binding->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp)); + QML_END_INSTR(StoreV8Binding) QML_BEGIN_INSTR(StoreValueSource) QObject *obj = stack.pop(); diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp index 0ee7d4dc7d..a7946d46db 100644 --- a/src/declarative/qml/v4/qdeclarativev4bindings.cpp +++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp @@ -315,6 +315,7 @@ void QDeclarativeV4BindingsPrivate::Binding::destroy() enabled = false; removeFromObject(); clear(); + removeError(); parent->q_func()->release(); } diff --git a/src/declarative/qml/v8/qv8bindings.cpp b/src/declarative/qml/v8/qv8bindings.cpp new file mode 100644 index 0000000000..424d06f083 --- /dev/null +++ b/src/declarative/qml/v8/qv8bindings.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv8bindings_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QV8BindingsPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QV8Bindings) +public: + QV8BindingsPrivate(); + + struct Binding : public QDeclarativeJavaScriptExpression, + public QDeclarativeAbstractBinding { + Binding(); + + // Inherited from QDeclarativeAbstractBinding + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags); + virtual void update(QDeclarativePropertyPrivate::WriteFlags flags); + virtual void destroy(); + + int index:30; + bool enabled:1; + bool updating:1; + int line; + QDeclarativeProperty property; + QV8BindingsPrivate *parent; + }; + + QUrl url; + int bindingsCount; + Binding *bindings; + v8::Persistent functions; +}; + +QV8BindingsPrivate::QV8BindingsPrivate() +: bindingsCount(0), bindings(0) +{ +} + +QV8BindingsPrivate::Binding::Binding() +: index(-1), enabled(false), updating(false), line(-1), parent(0) +{ +} + +void QV8BindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (enabled != e) { + enabled = e; + + if (e) update(flags); + } +} + +void QV8BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (!enabled) + return; + + QDeclarativeContextData *context = QDeclarativeAbstractExpression::context(); + if (!context || !context->isValid()) + return; + + if (!updating) { + updating = true; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); + + bool isUndefined = false; + + QDeclarativeDeleteWatcher watcher(this); + ep->referenceScarceResources(); + + v8::HandleScope handle_scope; + v8::Context::Scope scope(ep->v8engine.context()); + v8::Local result = evaluate(v8::Handle::Cast(parent->functions->Get(index)), + &isUndefined); + + bool needsErrorData = false; + if (!watcher.wasDeleted() && !error.isValid()) + needsErrorData = !QDeclarativeBindingPrivate::writeBindingResult(this, property, result, + isUndefined, flags); + + if (!watcher.wasDeleted()) { + + if (needsErrorData) { + QUrl url = QUrl(parent->url); + if (url.isEmpty()) url = QUrl(QLatin1String("")); + + error.setUrl(url); + error.setLine(line); + error.setColumn(-1); + } + + if (error.isValid()) { + if (!addError(ep)) ep->warning(error); + } else { + removeError(); + } + + updating = false; + } + + ep->dereferenceScarceResources(); + + } else { + QDeclarativeBindingPrivate::printBindingLoopError(property); + } +} + +void QV8BindingsPrivate::Binding::destroy() +{ + enabled = false; + removeFromObject(); + clear(); + removeError(); + parent->q_func()->release(); +} + +QV8Bindings::QV8Bindings(const QString &program, int line, + QDeclarativeCompiledData *compiled, + QDeclarativeContextData *context) +: QObject(*(new QV8BindingsPrivate)) +{ + Q_D(QV8Bindings); + + QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(context->engine); + + if (compiled->v8bindings.IsEmpty()) { + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + v8::Local script = engine->qmlModeCompile(program, compiled->name, line); + v8::Local result = script->Run(engine->contextWrapper()->sharedContext()); + + if (result->IsArray()) + compiled->v8bindings = qPersistentNew(v8::Local::Cast(result)); + } + + d->url = compiled->url; + d->functions = qPersistentNew(compiled->v8bindings); + d->bindingsCount = d->functions->Length(); + d->bindings = new QV8BindingsPrivate::Binding[d->bindingsCount]; + + setContext(context); +} + +QV8Bindings::~QV8Bindings() +{ + Q_D(QV8Bindings); + qPersistentDispose(d->functions); + + delete [] d->bindings; + d->bindings = 0; + d->bindingsCount = 0; +} + +QDeclarativeAbstractBinding *QV8Bindings::configBinding(int index, QObject *target, QObject *scope, + const QDeclarativeProperty &property, int line) +{ + Q_D(QV8Bindings); + QV8BindingsPrivate::Binding *rv = d->bindings + index; + + rv->line = line; + rv->index = index; + rv->property = property; + rv->setContext(context()); + rv->setScopeObject(scope); + rv->setUseSharedContext(true); + rv->setNotifyOnValueChanged(true); + rv->setNotifyObject(this, index); + rv->parent = d; + + addref(); // This is decremented in Binding::destroy() + + return rv; +} + +int QV8Bindings::qt_metacall(QMetaObject::Call c, int id, void **) +{ + Q_D(QV8Bindings); + + if (c == QMetaObject::InvokeMetaMethod) { + QV8BindingsPrivate::Binding *binding = d->bindings + id; + binding->update(QDeclarativePropertyPrivate::DontRemoveBinding); + } + return -1; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qv8bindings_p.h b/src/declarative/qml/v8/qv8bindings_p.h new file mode 100644 index 0000000000..e99e3c834d --- /dev/null +++ b/src/declarative/qml/v8/qv8bindings_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV8BINDINGS_P_H +#define QV8BINDINGS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativev4instruction_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDeclarativeCompiledData; + +class QV8BindingsPrivate; +class QV8Bindings : public QObject, + public QDeclarativeAbstractExpression, + public QDeclarativeRefCount +{ +public: + QV8Bindings(const QString &program, int line, + QDeclarativeCompiledData *compiled, + QDeclarativeContextData *context); + virtual ~QV8Bindings(); + + QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, + const QDeclarativeProperty &prop, int line); + +protected: + int qt_metacall(QMetaObject::Call, int, void **); + +private: + Q_DISABLE_COPY(QV8Bindings) + Q_DECLARE_PRIVATE(QV8Bindings) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QV8BINDINGS_P_H + + diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri index d91acd7759..61e0184884 100644 --- a/src/declarative/qml/v8/v8.pri +++ b/src/declarative/qml/v8/v8.pri @@ -14,6 +14,7 @@ HEADERS += \ $$PWD/qv8valuetypewrapper_p.h \ $$PWD/qv8include_p.h \ $$PWD/qv8worker_p.h \ + $$PWD/qv8bindings_p.h \ $$PWD/../../../3rdparty/javascriptcore/DateMath.h \ SOURCES += \ @@ -28,5 +29,6 @@ SOURCES += \ $$PWD/qv8valuetypewrapper.cpp \ $$PWD/qv8include.cpp \ $$PWD/qv8worker.cpp \ + $$PWD/qv8bindings.cpp \ $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \ -- cgit v1.2.3