diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-06-17 11:37:17 +1000 |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-06-17 11:37:17 +1000 |
commit | 69a17a912a41458a2b4a20bdbda1717920275250 (patch) | |
tree | f0eb0cdb210765ddb954539a0fbe520640eae2a1 | |
parent | 9c5e112e12f09ad5c8356d6815f9b23102e99bfd (diff) |
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.
19 files changed, 623 insertions, 131 deletions
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<v8::Value> 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<v8::Value> 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<BindingReference*> sharedBindings; + for (QHash<QDeclarativeParser::Value*,BindingReference>::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<QDeclarativeBinding*>()) { + 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<TypeReference> types; + v8::Persistent<v8::Array> 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<QString, QDeclarativeParser::Object *> ids; QHash<int, QDeclarativeParser::Object *> idIndexes; int parserStatusCount; @@ -304,6 +307,8 @@ private: bool nested; QByteArray compiledBindingData; + QString v8BindingProgram; + int v8BindingProgramLine; QHash<QDeclarativeParser::Value *, BindingReference> bindings; QHash<QDeclarativeParser::Value *, BindingContext> 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 <qscriptengine.h> #include <QtCore/qvarlengtharray.h> @@ -499,16 +500,16 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject QDeclarativeContextData::QDeclarativeContextData() : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false), publicContext(0), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), - expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), - linkedContext(0), componentAttached(0) + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + componentAttached(0), v4bindings(0), v8bindings(0) { } QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt) : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false), publicContext(ctxt), propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), - expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), - linkedContext(0), componentAttached(0) + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + componentAttached(0), v4bindings(0), v8bindings(0) { } @@ -607,8 +608,11 @@ void QDeclarativeContextData::destroy() if (imports) imports->release(); - 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<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr; @@ -476,7 +464,9 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F bool lastCaptureProperties = ep->captureProperties; QPODVector<QDeclarativeEnginePrivate::CapturedProperty> 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<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F ep->capturedProperties); } - 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<v8::Function>, 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 T> +class QDeclarativeRefPointer +{ +public: + inline QDeclarativeRefPointer(); + inline QDeclarativeRefPointer(T *); + inline QDeclarativeRefPointer(const QDeclarativeRefPointer<T> &); + inline ~QDeclarativeRefPointer(); + + inline QDeclarativeRefPointer<T> &operator=(const QDeclarativeRefPointer<T> &o); + inline QDeclarativeRefPointer<T> &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<class T> +QDeclarativeRefPointer<T>::QDeclarativeRefPointer() +: o(0) +{ +} + +template<class T> +QDeclarativeRefPointer<T>::QDeclarativeRefPointer(T *o) +: o(o) +{ + if (o) o->addref(); +} + +template<class T> +QDeclarativeRefPointer<T>::QDeclarativeRefPointer(const QDeclarativeRefPointer<T> &other) +: o(other.o) +{ + if (o) o->addref(); +} + +template<class T> +QDeclarativeRefPointer<T>::~QDeclarativeRefPointer() +{ + if (o) o->release(); +} + +template<class T> +QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::operator=(const QDeclarativeRefPointer<T> &other) +{ + if (other.o) other.o->addref(); + if (o) o->release(); + o = other.o; + return *this; +} + +template<class T> +QDeclarativeRefPointer<T> &QDeclarativeRefPointer<T>::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<QObject *> &stack, parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(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<QObject *> &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<QObject *> &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<QObject *> &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<QObject *> &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<QObject *> &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 <private/qv8_p.h> +#include <private/qdeclarativebinding_p.h> +#include <private/qdeclarativecompiler_p.h> +#include <private/qdeclarativebinding_p_p.h> +#include <private/qdeclarativeexpression_p.h> +#include <private/qobject_p.h> + +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<v8::Array> 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<v8::Value> result = evaluate(v8::Handle<v8::Function>::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("<Unknown File>")); + + 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<v8::Script> script = engine->qmlModeCompile(program, compiled->name, line); + v8::Local<v8::Value> result = script->Run(engine->contextWrapper()->sharedContext()); + + if (result->IsArray()) + compiled->v8bindings = qPersistentNew(v8::Local<v8::Array>::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 \ |