diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-10-04 17:18:15 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2014-10-09 17:41:39 +0200 |
commit | 9e71faae038de4c41c206f1321da1b37ab6ca8b1 (patch) | |
tree | bf8c38eecd7654b4178379778c218f7552a752d9 | |
parent | 8c3d661163fc7517569f1a70ab70c2b23de25406 (diff) |
Fix QQmlExpression/QQmlScriptString/QQmlBinding crashes
In the QQmlScriptString we store the binding id and it is an index into the
runtimeFunctions array of the compilation unit. However we don't store the
compilation unit and instead in QQmlBinding and QQmlExpression try to retrieve
it from the cache via the context url (we have the context after all). That
turns out to be not a reliable way, as sometimes the URL might slightly differ
from the originally compiled cache (qrc:/// turning to qrc:/ maybe).
Consequently the type is (unnecessarily) compiled again and unfortunately not
_linked_, therefore the runtime functions array is empty. Another option is
that when the component was created from a QByteArray, then no entry exists in
the cache in the first place.
This patch addresses the problem by storing a reference to the compilation unit
in the QQmlContextData. That we can safely retrieve and it'll make sure the
compilation unit also stays alive.
In the process of that the manual reference counting was switched over to
QQmlRefCount and QQmlRefPointer for QV4::CompilationUnit.
Task-number: QTBUG-41193
Change-Id: I9111f9a3b65618e453954abcd789c039e65a94f7
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
25 files changed, 87 insertions, 87 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a96fafac9b..b64e637739 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -538,7 +538,6 @@ Document::Document(bool debugMode) , program(0) , jsGenerator(&jsModule) , unitFlags(0) - , javaScriptCompilationUnit(0) { } @@ -1502,7 +1501,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement) QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) { - QV4::CompiledData::CompilationUnit *compilationUnit = output.javaScriptCompilationUnit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit; QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output); const uint unitSize = jsUnit->unitSize; diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index ddd9a22bc2..cc22023f8e 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -317,7 +317,7 @@ struct Q_QML_PRIVATE_EXPORT Document QV4::Compiler::JSUnitGenerator jsGenerator; quint32 unitFlags; - QV4::CompiledData::CompilationUnit *javaScriptCompilationUnit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit; QHash<int, QStringList> extraSignalParameters; QV4::CompiledData::TypeReferenceMap typeReferences; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 13367efc3d..6a97386767 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -232,8 +232,6 @@ bool QQmlTypeCompiler::compile() document->javaScriptCompilationUnit->data = qmlUnit; compiledData->compilationUnit = document->javaScriptCompilationUnit; - if (compiledData->compilationUnit) - compiledData->compilationUnit->ref(); // Add to type registry of composites if (compiledData->isCompositeType()) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index e5b7681a7c..6791970461 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -39,6 +39,7 @@ #include <QHash> #include <private/qv4value_p.h> #include <private/qv4executableallocator_p.h> +#include <private/qqmlrefcount_p.h> QT_BEGIN_NAMESPACE @@ -559,18 +560,16 @@ struct TypeReferenceMap : QHash<int, TypeReference> // CompilationUnit * (for functions that need to clean up) // CompiledData::Function *compiledFunction -struct Q_QML_PRIVATE_EXPORT CompilationUnit +struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount { #ifdef V4_BOOTSTRAP CompilationUnit() - : refCount(0) - , data(0) + : data(0) {} virtual ~CompilationUnit() {} #else CompilationUnit() - : refCount(0) - , data(0) + : data(0) , engine(0) , runtimeStrings(0) , runtimeLookups(0) @@ -580,10 +579,6 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit virtual ~CompilationUnit(); #endif - void ref() { ++refCount; } - void deref() { if (!--refCount) delete this; } - - int refCount; Unit *data; // Called only when building QML, when we build the header for JS first and append QML data diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 40a44844ce..39977375c4 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -446,13 +446,15 @@ void InstructionSelection::run(int functionIndex) delete[] codeStart; } -QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep() +QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() { compilationUnit->codeRefs.resize(irModule->functions.size()); int i = 0; foreach (IR::Function *irFunction, irModule->functions) compilationUnit->codeRefs[i++] = codeRefs[irFunction]; - return compilationUnit.take(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; + result.take(compilationUnit.take()); + return result; } void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 938b60ca05..89f575c633 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -66,7 +66,7 @@ public: virtual void run(int functionIndex); protected: - virtual QV4::CompiledData::CompilationUnit *backendCompileStep(); + virtual QQmlRefPointer<CompiledData::CompilationUnit> backendCompileStep(); virtual void visitJump(IR::Jump *); virtual void visitCJump(IR::CJump *); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index f160954f84..e419084238 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -72,12 +72,12 @@ EvalInstructionSelection::~EvalInstructionSelection() EvalISelFactory::~EvalISelFactory() {} -QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData) +QQmlRefPointer<CompiledData::CompilationUnit> EvalInstructionSelection::compile(bool generateUnitData) { for (int i = 0; i < irModule->functions.size(); ++i) run(i); - QV4::CompiledData::CompilationUnit *unit = backendCompileStep(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = backendCompileStep(); if (generateUnitData) unit->data = jsGenerator->generateUnit(); return unit; diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 984e8ab4bf..504d255eaf 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -57,7 +57,7 @@ public: EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); virtual ~EvalInstructionSelection() = 0; - QV4::CompiledData::CompilationUnit *compile(bool generateUnitData = true); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile(bool generateUnitData = true); void setUseFastLookups(bool b) { useFastLookups = b; } void setUseTypeInference(bool onoff) { useTypeInference = onoff; } @@ -74,7 +74,7 @@ public: protected: virtual void run(int functionIndex) = 0; - virtual QV4::CompiledData::CompilationUnit *backendCompileStep() = 0; + virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> backendCompileStep() = 0; bool useFastLookups; bool useTypeInference; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 5cf00f6d60..9ff33feff2 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -293,9 +293,11 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values) return finalValues.constData(); } -QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep() +QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() { - return compilationUnit.take(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; + result.take(compilationUnit.take()); + return result; } void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 2f64bf1157..8ad97c640b 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -66,7 +66,7 @@ public: const void *addConstantTable(QVector<QV4::Primitive> *values); protected: - virtual QV4::CompiledData::CompilationUnit *backendCompileStep(); + virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> backendCompileStep(); virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result); virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index cddc45aaf5..84b0eb17af 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -108,7 +108,7 @@ FunctionObject::Data::Data(InternalClass *ic) FunctionObject::Data::~Data() { if (function) - function->compilationUnit->deref(); + function->compilationUnit->release(); } void FunctionObject::init(String *n, bool createProto) @@ -226,7 +226,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) QV4::Compiler::JSUnitGenerator jsGenerator(&module); QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); - QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile(); QV4::Function *vmf = compilationUnit->linkToEngine(v4); return FunctionObject::createScriptFunction(v4->rootContext, vmf)->asReturnedValue(); @@ -416,7 +416,7 @@ SimpleScriptFunction::Data::Data(ExecutionContext *scope, Function *function, bo setVTable(staticVTable()); this->function = function; - function->compilationUnit->ref(); + function->compilationUnit->addref(); Q_ASSERT(function); Q_ASSERT(function->code); diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 8224f8a851..7c66ee0049 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -80,23 +80,23 @@ public: FunctionCall(Function *function, qint64 start, qint64 end) : m_function(function), m_start(start), m_end(end) - { m_function->compilationUnit->ref(); } + { m_function->compilationUnit->addref(); } FunctionCall(const FunctionCall &other) : m_function(other.m_function), m_start(other.m_start), m_end(other.m_end) - { m_function->compilationUnit->ref(); } + { m_function->compilationUnit->addref(); } ~FunctionCall() - { m_function->compilationUnit->deref(); } + { m_function->compilationUnit->release(); } FunctionCall &operator=(const FunctionCall &other) { if (&other != this) { if (m_function) - m_function->compilationUnit->deref(); + m_function->compilationUnit->release(); m_function = other.m_function; m_start = other.m_start; m_end = other.m_end; - m_function->compilationUnit->ref(); + m_function->compilationUnit->addref(); } return *this; } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 8e91c0e6a5..fa4b4b1894 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -62,7 +62,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml) setVTable(staticVTable()); function = f; if (function) - function->compilationUnit->ref(); + function->compilationUnit->addref(); needsActivation = function ? function->needsActivation() : false; Scope s(scope); @@ -163,14 +163,9 @@ struct CompilationUnitHolder : public Object : Object::Data(engine) , unit(unit) { - unit->ref(); setVTable(staticVTable()); } - ~Data() - { - unit->deref(); - } - QV4::CompiledData::CompilationUnit *unit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit; }; V4_OBJECT(Object) @@ -264,7 +259,7 @@ void Script::parse() QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); if (inheritContext) isel->setUseFastLookups(false); - QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile(); vmFunction = compilationUnit->linkToEngine(v4); ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); compilationUnitHolder = holder.asReturnedValue(); @@ -313,7 +308,7 @@ Function *Script::function() return vmFunction; } -QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors) +QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors) { using namespace QQmlJS; using namespace QQmlJS::AST; diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 28ac5f3e01..ed93ce49ae 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -122,7 +122,7 @@ struct Q_QML_EXPORT Script { Function *function(); - static QV4::CompiledData::CompilationUnit *precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0); + static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0); static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject); }; diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 27f609bf39..3f1d252862 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -47,11 +47,12 @@ #include <QtCore/qglobal.h> #include <QtCore/qatomic.h> +#include <private/qtqmlglobal_p.h> QT_BEGIN_NAMESPACE -class QQmlRefCount +class Q_QML_PRIVATE_EXPORT QQmlRefCount { public: inline QQmlRefCount(); diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 8b6bc81935..6033395629 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -93,17 +93,10 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine()); - if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { - QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url); - Q_ASSERT(typeData); - - if (QQmlCompiledData *cdata = typeData->compiledData()) { - url = cdata->fileName(); - if (scriptPrivate->bindingId != QQmlBinding::Invalid) - runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); - } - - typeData->release(); + if (engine && ctxtdata && !ctxtdata->url.isEmpty() && ctxtdata->typeCompilationUnit) { + url = ctxtdata->url.toString(); + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } setNotifyOnValueChanged(true); diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp index eca8070b3f..22838786b6 100644 --- a/src/qml/qml/qqmlcompileddata.cpp +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) : engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false), - rootPropertyCache(0), compilationUnit(0), totalBindingsCount(0), totalParserStatusCount(0) + rootPropertyCache(0), totalBindingsCount(0), totalParserStatusCount(0) { Q_ASSERT(engine); } @@ -92,9 +92,6 @@ QQmlCompiledData::~QQmlCompiledData() if (rootPropertyCache) rootPropertyCache->release(); - - if (compilationUnit) - compilationUnit->deref(); } void QQmlCompiledData::clear() diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 11646fc6b8..5e76533739 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -123,7 +123,7 @@ public: QVector<QQmlPropertyCache *> propertyCaches; QList<QQmlScriptData *> scripts; - QV4::CompiledData::CompilationUnit *compilationUnit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; // index in first hash is component index, hash inside maps from object index in that scope to integer id QHash<int, QHash<int, int> > objectIndexToIdPerComponent; QHash<int, int> objectIndexToIdForRoot; diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index d3f283357a..233ea4d34a 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -141,6 +141,9 @@ public: // VME data that is constructing this context if any void *activeVMEData; + // Compilation unit for contexts that belong to a compiled type. + QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit; + // Property name cache QV4::IdentifierHash<int> propertyNames; diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 22e74135b5..947b55f15d 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -148,20 +148,13 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt if (scriptPrivate->context) { QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine()); - if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { - QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url); - Q_ASSERT(typeData); + if (engine && ctxtdata && !ctxtdata->url.isEmpty() && ctxtdata->typeCompilationUnit) { + d->url = ctxtdata->url.toString(); + d->line = scriptPrivate->lineNumber; + d->column = scriptPrivate->columnNumber; - if (QQmlCompiledData *cdata = typeData->compiledData()) { - d->url = cdata->fileName(); - d->line = scriptPrivate->lineNumber; - d->column = scriptPrivate->columnNumber; - - if (scriptPrivate->bindingId != QQmlBinding::Invalid) - runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); - } - - typeData->release(); + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index a827e96ab1..42cac66fbd 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -180,6 +180,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context->urlString = compiledData->fileName(); context->imports = compiledData->importCache; context->imports->addref(); + context->typeCompilationUnit = compiledData->compilationUnit; context->setParent(parentContext); if (!sharedState->rootContext) { @@ -753,7 +754,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4 // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = binding->value.compiledScriptIndex; + ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 0e2d4d027a..1b222fe1a3 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2541,7 +2541,6 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData: QQmlScriptData::QQmlScriptData() : importCache(0) , m_loaded(false) - , m_precompiledScript(0) , m_program(0) { } @@ -2549,10 +2548,6 @@ QQmlScriptData::QQmlScriptData() QQmlScriptData::~QQmlScriptData() { delete m_program; - if (m_precompiledScript) { - m_precompiledScript->deref(); - m_precompiledScript = 0; - } } void QQmlScriptData::initialize(QQmlEngine *engine) @@ -2713,13 +2708,10 @@ void QQmlScriptBlob::dataReceived(const Data &data) } QList<QQmlError> errors; - QV4::CompiledData::CompilationUnit *unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors); - if (unit) - unit->ref(); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors); + // No need to addref on unit, it's initial refcount is 1 source.clear(); if (!errors.isEmpty()) { - if (unit) - unit->deref(); setError(errors); return; } @@ -2732,7 +2724,6 @@ void QQmlScriptBlob::dataReceived(const Data &data) unit->data = unitData; initializeFromCompilationUnit(unit); - unit->deref(); } void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) @@ -2805,8 +2796,6 @@ void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::Compilatio m_scriptData->url = finalUrl(); m_scriptData->urlString = finalUrlString(); m_scriptData->m_precompiledScript = unit; - if (m_scriptData->m_precompiledScript) - m_scriptData->m_precompiledScript->ref(); m_importCache.setBaseUrl(finalUrl(), finalUrlString()); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 9f98e4fd40..3b5aa1ec7a 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -513,7 +513,7 @@ private: void initialize(QQmlEngine *); bool m_loaded; - QV4::CompiledData::CompilationUnit *m_precompiledScript; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_precompiledScript; QV4::Script *m_program; QV4::PersistentValue m_value; }; diff --git a/tests/auto/qml/qqmlexpression/data/expressionFromDataComponent.qml b/tests/auto/qml/qqmlexpression/data/expressionFromDataComponent.qml new file mode 100644 index 0000000000..1aefdf0c42 --- /dev/null +++ b/tests/auto/qml/qqmlexpression/data/expressionFromDataComponent.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import Test 1.0 +TestObject { + scriptString: { return "success"; } +} + diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp index 12cb2dce83..f53ef82891 100644 --- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp +++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp @@ -47,6 +47,7 @@ public: private slots: void scriptString(); void syntaxError(); + void expressionFromDataComponent(); }; class TestObject : public QObject @@ -108,6 +109,31 @@ void tst_qqmlexpression::syntaxError() QCOMPARE(v, QVariant()); } +void tst_qqmlexpression::expressionFromDataComponent() +{ + qmlRegisterType<TestObject>("Test", 1, 0, "TestObject"); + + QQmlEngine engine; + QQmlComponent c(&engine); + + QUrl url = testFileUrl("expressionFromDataComponent.qml"); + + { + QFile f(url.toLocalFile()); + QVERIFY(f.open(QIODevice::ReadOnly)); + c.setData(f.readAll(), url); + } + + QScopedPointer<TestObject> object; + object.reset(qobject_cast<TestObject*>(c.create())); + Q_ASSERT(!object.isNull()); + + QQmlExpression expression(object->scriptString()); + QVariant result = expression.evaluate(); + QVERIFY(result.type() == QVariant::String); + QCOMPARE(result.toString(), QStringLiteral("success")); +} + QTEST_MAIN(tst_qqmlexpression) #include "tst_qqmlexpression.moc" |