diff options
Diffstat (limited to 'src/qml/qml')
50 files changed, 662 insertions, 1062 deletions
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index c49463c913..700e5c3324 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -127,6 +127,7 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q) : q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false), m_mainThreadWaiting(false), mainSync(0), m_mainObject(this) { + setObjectName(QStringLiteral("QQmlThread")); } bool QQmlThreadPrivate::event(QEvent *e) diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 33d8be37d1..013f757c90 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -1,4 +1,12 @@ SOURCES += \ + $$PWD/qqmldirparser.cpp \ + +HEADERS += \ + $$PWD/qqmldirparser_p.h \ + +!qmldevtools_build { + +SOURCES += \ $$PWD/qqmlopenmetaobject.cpp \ $$PWD/qqmlvmemetaobject.cpp \ $$PWD/qqmlengine.cpp \ @@ -20,7 +28,6 @@ SOURCES += \ $$PWD/qqmltypeloader.cpp \ $$PWD/qqmlinfo.cpp \ $$PWD/qqmlerror.cpp \ - $$PWD/qqmlscript.cpp \ $$PWD/qqmlvaluetype.cpp \ $$PWD/qqmlaccessors.cpp \ $$PWD/qqmlxmlhttprequest.cpp \ @@ -32,7 +39,6 @@ SOURCES += \ $$PWD/qqmltypenamecache.cpp \ $$PWD/qqmlscriptstring.cpp \ $$PWD/qqmlnetworkaccessmanagerfactory.cpp \ - $$PWD/qqmldirparser.cpp \ $$PWD/qqmlextensionplugin.cpp \ $$PWD/qqmlimport.cpp \ $$PWD/qqmllist.cpp \ @@ -91,7 +97,6 @@ HEADERS += \ $$PWD/qqmllist_p.h \ $$PWD/qqmldata_p.h \ $$PWD/qqmlerror.h \ - $$PWD/qqmlscript_p.h \ $$PWD/qqmlvaluetype_p.h \ $$PWD/qqmlaccessors_p.h \ $$PWD/qqmlxmlhttprequest_p.h \ @@ -104,7 +109,6 @@ HEADERS += \ $$PWD/qqmlscriptstring.h \ $$PWD/qqmlguard_p.h \ $$PWD/qqmlnetworkaccessmanagerfactory.h \ - $$PWD/qqmldirparser_p.h \ $$PWD/qqmlextensioninterface.h \ $$PWD/qqmlimport_p.h \ $$PWD/qqmlextensionplugin.h \ @@ -135,3 +139,5 @@ HEADERS += \ include(ftw/ftw.pri) include(v8/v8.pri) + +} diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 6479aedd1b..721f2cc5a8 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -91,13 +91,13 @@ class QQmlPropertyValueInterceptor; const char *className = T::staticMetaObject.className(); \ const int nameLen = int(strlen(className)); \ QVarLengthArray<char,48> pointerName(nameLen+2); \ - memcpy(pointerName.data(), className, nameLen); \ + memcpy(pointerName.data(), className, size_t(nameLen)); \ pointerName[nameLen] = '*'; \ pointerName[nameLen+1] = '\0'; \ const int listLen = int(strlen("QQmlListProperty<")); \ QVarLengthArray<char,64> listName(listLen + nameLen + 2); \ - memcpy(listName.data(), "QQmlListProperty<", listLen); \ - memcpy(listName.data()+listLen, className, nameLen); \ + memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \ + memcpy(listName.data()+listLen, className, size_t(nameLen)); \ listName[listLen+nameLen] = '>'; \ listName[listLen+nameLen+1] = '\0'; diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index 7354f9af1e..0bc0b6f199 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -149,7 +149,6 @@ private: friend class QQmlComponentPrivate; friend class QQmlValueTypeProxyBinding; friend class QQmlPropertyPrivate; - friend class QQmlVME; friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>; friend class QV4Bindings; friend class QQmlObjectCreator; diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp index 127dad86ce..3aea9c83cc 100644 --- a/src/qml/qml/qqmlabstracturlinterceptor.cpp +++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp @@ -84,8 +84,8 @@ /*! \fn QUrl QQmlAbstractUrlInterceptor::intercept(const QUrl& url, DataType type) - A pure virtual function where you can intercept the url. The returned value is taken as the - new value for the url. The type of url being intercepted is given by the type variable. + A pure virtual function where you can intercept the \a url. The returned value is taken as the + new value for the url. The type of url being intercepted is given by the \a type variable. Your implementation of this function must be thread-safe, as it can be called from multiple threads at the same time. diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 295461ba26..571d78312e 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -88,11 +88,8 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt) if (QQmlCompiledData *cdata = typeData->compiledData()) { QV4::ExecutionEngine *v4 = engine->v4engine(); QV4::Scope valueScope(v4); - QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(v4->v8Engine, ctxtdata, obj)); - QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject)); - QV4::ExecutionContext *qmlContext = wrapper->context(); QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]]; - QV4::ScopedValue function(valueScope, QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction)); + QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction)); rv = new QQmlBinding(function, obj, ctxtdata); } @@ -128,31 +125,33 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte return; QString url; - QString code; - - int id = scriptPrivate->bindingId; - if (id >= 0) { - 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()) { - code = cdata->primitives.at(id); - url = cdata->name; - } + QV4::Function *runtimeFunction = 0; + + 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); - typeData->release(); + if (QQmlCompiledData *cdata = typeData->compiledData()) { + url = cdata->name; + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } - } else - code = scriptPrivate->script; + + typeData->release(); + } setNotifyOnValueChanged(true); QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); setScopeObject(obj ? obj : scriptPrivate->scope); - v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + if (runtimeFunction) { + v4function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, scopeObject(), runtimeFunction); + } else { + QString code = scriptPrivate->script; + v4function = qmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + } } QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) @@ -215,7 +214,7 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) QV4::ScopedFunctionObject f(scope, v4function.value()); Q_ASSERT(f); if (f->bindingKeyFlag) { - QQmlSourceLocation loc = f->as<QQmlBindingFunction>()->bindingLocation; + QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->bindingLocation; url = loc.sourceFile; lineNumber = loc.line; columnNumber = loc.column; diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 6237459aac..876f367097 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -52,6 +52,7 @@ #include "qqmlglobal_p.h" #include <private/qqmlprofiler_p.h> #include <private/qv4debugservice_p.h> +#include <private/qqmlcompiler_p.h> #include "qqmlinfo.h" #include <private/qv4value_inl_p.h> @@ -59,6 +60,7 @@ #include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> + QT_BEGIN_NAMESPACE static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = { @@ -105,6 +107,28 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, init(ctxt, scope); } +QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) + : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + m_target(target), + m_index(index), + m_extra(0) +{ + setExpressionFunctionValid(true); + setInvalidParameterName(false); + + // It's important to call init first, because m_index gets remapped in case of cloned signals. + init(ctxt, scope); + + QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); + QString error; + m_v8function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, scope, runtimeFunction, signal.parameterNames(), &error); + if (!error.isEmpty()) { + qmlInfo(scopeObject()) << error; + setInvalidParameterName(true); + } else + setInvalidParameterName(false); +} + void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope) { setNotifyOnValueChanged(false); @@ -221,7 +245,7 @@ void QQmlBoundSignalExpression::evaluate(void **a) m_extra->m_parameterString.clear(); m_v8function = evalFunction(context(), scopeObject(), expression, - m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_v8qmlscope); + m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope); if (m_v8function.isNullOrUndefined()) { ep->dereferenceScarceResources(); diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index 6df6da4214..43ff71f682 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -78,6 +78,8 @@ public: QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function); + QQmlBoundSignalExpression(QObject *target, int index, + QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction); // "inherited" from QQmlJavaScriptExpression. static QString expressionIdentifier(QQmlJavaScriptExpression *); @@ -104,7 +106,6 @@ private: bool invalidParameterName() const { return m_extra.flag2(); } void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } - QV4::PersistentValue m_v8qmlscope; QV4::PersistentValue m_v8function; QObject *m_target; @@ -119,6 +120,7 @@ private: QString m_parameterString; QString m_expression; QQmlSourceLocation m_sourceLocation; + QV4::PersistentValue m_v8qmlscope; }; // We store some flag bits in the following flag pointers. diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp index 59c56bf513..a352e5ad1d 100644 --- a/src/qml/qml/qqmlcompileddata.cpp +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -61,8 +61,6 @@ QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) rootPropertyCache(0), compilationUnit(0), qmlUnit(0), totalBindingsCount(0), totalParserStatusCount(0) { Q_ASSERT(engine); - - bytecode.reserve(1024); } void QQmlCompiledData::destroy() diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 98d308aa5c..f3b6f621ce 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -55,13 +55,11 @@ #include "qqml.h" #include "qqmlerror.h" -#include "qqmlscript_p.h" #include "qqmlengine_p.h" #include <private/qbitfield_p.h> #include "qqmlpropertycache_p.h" #include "qqmltypenamecache_p.h" #include "qqmltypeloader_p.h" -#include <private/qqmlcodegenerator_p.h> #include "private/qv4identifier_p.h" #include <private/qqmljsastfwd_p.h> #include "qqmlcustomparser_p.h" @@ -129,15 +127,10 @@ public: QHash<int, TypeReference*> resolvedTypes; QQmlPropertyCache *rootPropertyCache; - QList<QString> primitives; - QVector<QByteArray> datas; - QByteArray bytecode; + QVector<QByteArray> metaObjects; QVector<QQmlPropertyCache *> propertyCaches; - QList<QVector<QQmlContextData::ObjectIdMapping> > contextCaches; QList<QQmlScriptData *> scripts; - QList<QUrl> urls; - // --- new compiler QV4::CompiledData::CompilationUnit *compilationUnit; QV4::CompiledData::QmlUnit *qmlUnit; // index in first hash is component index, hash inside maps from object index in that scope to integer id @@ -156,11 +149,14 @@ public: int totalObjectCount; // Number of objects explicitly instantiated bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } - bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); } + bool isCompositeType() const { return !metaObjects.at(qmlUnit->indexOfRootObject).isEmpty(); } bool isInitialized() const { return hasEngine(); } void initialize(QQmlEngine *); + QV4::Function *functionForBindingId(int bindingId) const + { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; } + protected: virtual void destroy(); // From QQmlRefCount virtual void clear(); // From QQmlCleanup diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 77d02e071f..39a7d8905d 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -51,7 +51,6 @@ #include "qqmlengine.h" #include "qqmlbinding_p.h" #include "qqmlglobal_p.h" -#include "qqmlscript_p.h" #include <private/qqmlenginedebugservice_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" @@ -264,14 +263,14 @@ V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); */ /*! - \qmlattachedsignal Component::onCompleted() + \qmlattachedsignal Component::completed() Emitted after component "startup" has completed. This can be used to execute script code at startup, once the full QML environment has been established. - The \c {Component::onCompleted} attached property can be declared on - any object. The order of running the \c onCompleted scripts is + The corresponding handler is \c onCompleted. It can be declared on + any object. The order of running the \c onCompleted handlers is undefined. \qml @@ -285,16 +284,16 @@ V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); */ /*! - \qmlattachedsignal Component::onDestruction() + \qmlattachedsignal Component::destruction() Emitted as the component begins destruction. This can be used to undo - work done in the onCompleted signal, or other imperative code in your - application. + work done in response to the \l {completed}{completed()} signal, or other + imperative code in your application. - The \c {Component::onDestruction} attached property can be declared on + The corresponding handler is \c onDestruction. It can be declared on any object. However, it applies to the destruction of the component as a whole, and not the destruction of the specific object. The order of - running the \c onDestruction scripts is undefined. + running the \c onDestruction handlers is undefined. \qml Rectangle { diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 4aa0daf47e..9be1990adc 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -127,7 +127,6 @@ private: QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent); Q_DISABLE_COPY(QQmlComponent) - friend class QQmlVME; friend class QQmlTypeData; friend class QQmlObjectCreator; }; diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h index ae416dcb1c..4fb77a1a4d 100644 --- a/src/qml/qml/qqmlcomponentattached_p.h +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -73,7 +73,6 @@ Q_SIGNALS: void destruction(); private: - friend class QQmlVME; friend class QQmlContextData; }; diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index e191807cf4..828ae8c523 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -88,7 +88,6 @@ public: QUrl baseUrl() const; private: - friend class QQmlVME; friend class QQmlEngine; friend class QQmlEnginePrivate; friend class QQmlExpression; diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 464bee82c0..2d544b1633 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -59,7 +59,6 @@ #include "qqmltypenamecache_p.h" #include "qqmlnotifier_p.h" #include "qqmllist.h" -#include "qqmlscript_p.h" #include <QtCore/qhash.h> #include <QtQml/qjsvalue.h> @@ -106,7 +105,6 @@ public: static QObject *context_at(QQmlListProperty<QObject> *, int); }; -class QQmlVME; class QQmlComponentAttached; class QQmlGuardedContextData; class Q_QML_PRIVATE_EXPORT QQmlContextData diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index e72e90296f..a5574b706a 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -94,7 +94,7 @@ ReturnedValue QmlContextWrapper::urlScope(QV8Engine *v8, const QUrl &url) context->isInternal = true; context->isJSContext = true; - Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0)); + Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0, true)); w->isNullWrapper = true; return w.asReturnedValue(); } @@ -387,6 +387,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings); } + Q_ASSERT(qmlContext->contextObject); const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; for (int i = 0; i < contextPropertyDependencyCount; ++i) { @@ -460,6 +461,9 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr return Encode::undefined(); } + if (hasProperty) + *hasProperty = true; + ExecutionEngine *v4 = m->engine(); QQmlEnginePrivate *ep = v4->v8Engine->engine() ? QQmlEnginePrivate::get(v4->v8Engine->engine()) : 0; if (ep) diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 16e3abf3a0..75acbdb778 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -47,8 +47,6 @@ QT_BEGIN_NAMESPACE -using namespace QQmlScript; - /*! \class QQmlCustomParser \brief The QQmlCustomParser class allows you to add new arbitrary types to QML. @@ -102,7 +100,7 @@ void QQmlCustomParser::clearErrors() An error is generated referring to the \a location in the source file. */ -void QQmlCustomParser::error(const CompiledData::Location &location, const QString &description) +void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; error.setLine(location.line); @@ -144,11 +142,6 @@ QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledD return compiler->bindingIdentifier(binding, this); } -QQmlJS::AST::Node *QQmlCustomParser::astForBinding(int objectIndex, int scriptIndex) const -{ - return compiler->astForBinding(objectIndex, scriptIndex); -} - struct StaticQtMetaObject : public QObject { static const QMetaObject *get() diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index 8d98cf6423..2ce6375870 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -55,7 +55,6 @@ #include "qqmlmetatype_p.h" #include "qqmlerror.h" -#include "qqmlscript_p.h" #include "qqmlbinding_p.h" #include <QtCore/qbytearray.h> @@ -63,6 +62,8 @@ QT_BEGIN_NAMESPACE +class QQmlCompiledData; + struct QQmlCustomParserCompilerBackend { virtual ~QQmlCustomParserCompilerBackend() {} @@ -72,8 +73,6 @@ struct QQmlCustomParserCompilerBackend const QMetaObject *resolveType(const QString& name) const; virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; } - - virtual QQmlJS::AST::Node *astForBinding(int, int) const { return 0; } }; class Q_QML_PRIVATE_EXPORT QQmlCustomParser @@ -93,8 +92,8 @@ public: void clearErrors(); Flags flags() const { return m_flags; } - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings) = 0; - virtual void setCustomData(QObject *, const QByteArray &)=0; + virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0; + virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0; QList<QQmlError> errors() const { return exceptions; } @@ -111,8 +110,6 @@ protected: QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding); - QQmlJS::AST::Node *astForBinding(int objectIndex, int scriptIndex) const; - private: QList<QQmlError> exceptions; QQmlCustomParserCompilerBackend *compiler; diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index c1d0132c61..a2b4b5edd0 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -41,9 +41,7 @@ #include "qqmldirparser_p.h" #include "qqmlerror.h" -#include "qqmlglobal_p.h" -#include <QtQml/qqmlfile.h> #include <QtCore/QtDebug> QT_BEGIN_NAMESPACE @@ -281,10 +279,10 @@ bool QQmlDirParser::parse(const QString &source) void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description) { - QQmlError error; - error.setLine(line); - error.setColumn(column); - error.setDescription(description); + QQmlJS::DiagnosticMessage error; + error.loc.startLine = line; + error.loc.startColumn = column; + error.message = description; _errors.append(error); } @@ -296,25 +294,41 @@ bool QQmlDirParser::hasError() const return false; } +#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) +QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const +{ + QList<QQmlJS::DiagnosticMessage> errors = _errors; + for (int i = 0; i < errors.size(); ++i) { + QQmlJS::DiagnosticMessage &msg = errors[i]; + msg.message.replace(QLatin1String("$$URI$$"), uri); + } + return errors; +} +#else void QQmlDirParser::setError(const QQmlError &e) { _errors.clear(); - _errors.append(e); + reportError(e.line(), e.column(), e.description()); } QList<QQmlError> QQmlDirParser::errors(const QString &uri) const { QUrl url(uri); - QList<QQmlError> errors = _errors; - for (int i = 0; i < errors.size(); ++i) { - QQmlError &e = errors[i]; - QString description = e.description(); + QList<QQmlError> errors; + for (int i = 0; i < _errors.size(); ++i) { + const QQmlJS::DiagnosticMessage &msg = _errors.at(i); + QQmlError e; + QString description = msg.message; description.replace(QLatin1String("$$URI$$"), uri); e.setDescription(description); e.setUrl(url); + e.setLine(msg.loc.startLine); + e.setColumn(msg.loc.startColumn); + errors << e; } return errors; } +#endif QString QQmlDirParser::typeNamespace() const { @@ -331,7 +345,7 @@ QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const return _plugins; } -QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirParser::components() const +QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const { return _components; } diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h index e3607d1e72..bcdb366c6c 100644 --- a/src/qml/qml/qqmldirparser_p.h +++ b/src/qml/qml/qqmldirparser_p.h @@ -56,13 +56,14 @@ #include <QtCore/QUrl> #include <QtCore/QHash> #include <QtCore/QDebug> -#include <private/qhashedstring_p.h> +#include <private/qqmljsengine_p.h> +#include <private/qtqmlglobal_p.h> QT_BEGIN_NAMESPACE class QQmlError; class QQmlEngine; -class Q_AUTOTEST_EXPORT QQmlDirParser +class Q_QML_PRIVATE_EXPORT QQmlDirParser { Q_DISABLE_COPY(QQmlDirParser) @@ -73,8 +74,12 @@ public: bool parse(const QString &source); bool hasError() const; +#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) + QList<QQmlJS::DiagnosticMessage> errors(const QString &uri) const; +#else void setError(const QQmlError &); QList<QQmlError> errors(const QString &uri) const; +#endif QString typeNamespace() const; void setTypeNamespace(const QString &s); @@ -121,7 +126,7 @@ public: int minorVersion; }; - QHash<QHashedStringRef,Component> components() const; + QHash<QString,Component> components() const; QList<Script> scripts() const; QList<Plugin> plugins() const; @@ -142,9 +147,9 @@ private: void reportError(quint16 line, quint16 column, const QString &message); private: - QList<QQmlError> _errors; + QList<QQmlJS::DiagnosticMessage> _errors; QString _typeNamespace; - QHash<QHashedStringRef,Component> _components; // multi hash + QHash<QString,Component> _components; // multi hash QList<Script> _scripts; QList<Plugin> _plugins; #ifdef QT_CREATOR @@ -152,7 +157,7 @@ private: #endif }; -typedef QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirComponents; +typedef QHash<QString,QQmlDirParser::Component> QQmlDirComponents; typedef QList<QQmlDirParser::Script> QQmlDirScripts; typedef QList<QQmlDirParser::Plugin> QQmlDirPlugins; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d927a8c628..d378d77bb0 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -109,7 +109,9 @@ #include <qlibrary.h> #include <windows.h> -#define CSIDL_APPDATA 0x001a // <username>\Application Data +#ifndef CSIDL_APPDATA +# define CSIDL_APPDATA 0x001a // <username>\Application Data +#endif #endif Q_DECLARE_METATYPE(QQmlProperty) @@ -2302,12 +2304,23 @@ static inline QString shellNormalizeFileName(const QString &name) { const QString nativeSeparatorName(QDir::toNativeSeparators(name)); const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16()); +// The correct declaration of the SHGetPathFromIDList symbol is +// being used in mingw-w64 as of r6215, which is a v3 snapshot. +#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) + ITEMIDLIST file; + if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL))) + return name; + TCHAR buffer[MAX_PATH]; + if (!SHGetPathFromIDList(&file, buffer)) + return name; +#else PIDLIST_ABSOLUTE file; if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL))) return name; TCHAR buffer[MAX_PATH]; if (!SHGetPathFromIDList(file, buffer)) return name; +#endif QString canonicalName = QString::fromWCharArray(buffer); // Upper case drive letter if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':')) diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 56c80dc2cd..5767ca90f0 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -69,6 +69,7 @@ #include "qqmldirparser_p.h" #include <private/qintrusivelist_p.h> #include <private/qrecyclepool_p.h> +#include <private/qfieldlist_p.h> #include <QtCore/qlist.h> #include <QtCore/qpair.h> diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index b64dd9bd39..4dc3704bbb 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -78,17 +78,10 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb expressionFunctionValid = false; } -void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, - QObject *me, const QString &srcUrl, - quint16 lineNumber, quint16 columnNumber) +void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFunction, QObject *me) { - url = srcUrl; - line = lineNumber; - column = columnNumber; - - expression = expr; - - expressionFunctionValid = false; + expressionFunctionValid = true; + function = QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxt, me, runtimeFunction); QQmlAbstractExpression::setContext(ctxt); setScopeObject(me); @@ -156,9 +149,9 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) return; - bool defaultConstruction = true; QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context); QObject *scopeObject = scope ? scope : scriptPrivate->scope; + QV4::Function *runtimeFunction = 0; if (scriptPrivate->context) { QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context); @@ -168,23 +161,22 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt Q_ASSERT(typeData); if (QQmlCompiledData *cdata = typeData->compiledData()) { - int id = scriptPrivate->bindingId; - if (id >= 0) { - defaultConstruction = false; - d->init(evalCtxtData, cdata->primitives.at(id), scopeObject, - cdata->name, scriptPrivate->lineNumber, scriptPrivate->columnNumber); - } else { - d->url = cdata->name; - d->line = scriptPrivate->lineNumber; - d->column = scriptPrivate->columnNumber; - } + d->url = cdata->name; + d->line = scriptPrivate->lineNumber; + d->column = scriptPrivate->columnNumber; + + if (scriptPrivate->bindingId != QQmlBinding::Invalid) + runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } typeData->release(); } } - if (defaultConstruction) + if (runtimeFunction) { + d->expression = scriptPrivate->script; + d->init(evalCtxtData, runtimeFunction, scopeObject); + } else d->init(evalCtxtData, scriptPrivate->script, scopeObject); } diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h index b702a37ee0..185b9542c5 100644 --- a/src/qml/qml/qqmlexpression.h +++ b/src/qml/qml/qqmlexpression.h @@ -98,7 +98,6 @@ private: Q_DECLARE_PRIVATE(QQmlExpression) friend class QQmlDebugger; friend class QQmlContext; - friend class QQmlVME; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index e84d193837..5488459962 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -77,7 +77,7 @@ public: ~QQmlExpressionPrivate(); void init(QQmlContextData *, const QString &, QObject *); - void init(QQmlContextData *, const QString &, QObject *, const QString &, quint16, quint16); + void init(QQmlContextData *, QV4::Function *runtimeFunction, QObject *); QVariant value(bool *isUndefined = 0); diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index 76de2dfe34..f3d1ba9d41 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE as a new QML element. It provides the current time through \c hour and \c minute properties, like this: - \snippet plugins/plugin.cpp 0 + \snippet qmlextensionplugins/plugin.cpp 0 \dots To make this class available as a QML type, create a plugin that registers @@ -85,7 +85,7 @@ QT_BEGIN_NAMESPACE module will be named \c TimeExample (as defined in the project file further below). - \snippet plugins/plugin.cpp plugin + \snippet qmlextensionplugins/plugin.cpp plugin This registers the \c TimeModel class with the 1.0 version of this plugin library, as a QML type called \c Time. The Q_ASSERT statement @@ -109,14 +109,14 @@ QT_BEGIN_NAMESPACE should be bundled with the plugin, so it needs to be specified in the \c qmldir file: - \quotefile plugins/imports/TimeExample/qmldir + \quotefile qmlextensionplugins/imports/TimeExample/qmldir Once the project is built and installed, the new \c Time element can be used by any QML component that imports the \c TimeExample module: - \snippet plugins/plugins.qml 0 + \snippet qmlextensionplugins/plugins.qml 0 - The full source code is available in the \l {qml/plugins}{plugins example}. + The full source code is available in the \l {qml/qmlextensionplugins}{plugins example}. The \l {Writing QML Extensions with C++} tutorial also contains a chapter on creating QML plugins. diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index be9b011dda..6728fa10a7 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -666,18 +666,13 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url) static QString toLocalFile(const QString &url) { - if (!url.startsWith(QLatin1String("file://"), Qt::CaseInsensitive)) + const QUrl file(url); + if (!file.isLocalFile()) return QString(); - QString file = url.mid(7); - //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt" - // magic for drives on windows - if (file.length() > 2 && file.at(0) == QLatin1Char('/') && file.at(2) == QLatin1Char(':')) - file.remove(0, 1); - - return file; + return file.toLocalFile(); } /*! diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp index a18b8327b1..187c3656c6 100644 --- a/src/qml/qml/qqmlfileselector.cpp +++ b/src/qml/qml/qqmlfileselector.cpp @@ -152,8 +152,8 @@ void QQmlFileSelector::setSelector(QFileSelector *selector) } /*! - Adds extra selectors to the current QFileSelector being used. Use this when - extra selectors are all you need to avoid having to create your own + Adds extra selectors contained in \a strings to the current QFileSelector being used. + Use this when extra selectors are all you need to avoid having to create your own QFileSelector instance. */ void QQmlFileSelector::setExtraSelectors(QStringList &strings) @@ -163,7 +163,7 @@ void QQmlFileSelector::setExtraSelectors(QStringList &strings) } /*! - Gets the QQmlFileSelector currently active on the target engine. + Gets the QQmlFileSelector currently active on the target \a engine. */ QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine) { diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index cae8365598..c0b21a943f 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -296,7 +296,7 @@ public: QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, - int vmaj, int vmin, QQmlScript::Import::Type type, + int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence = false); bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, @@ -624,12 +624,13 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader, } } - QQmlDirComponents::ConstIterator it = qmlDirComponents.find(type), end = qmlDirComponents.end(); + const QString typeStr = type.toString(); + QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end(); if (it != end) { QString componentUrl; bool isCompositeSingleton = false; QQmlDirComponents::ConstIterator candidate = end; - for ( ; it != end && it.key() == type; ++it) { + for ( ; it != end && it.key() == typeStr; ++it) { const QQmlDirParser::Component &c = *it; // importing version -1 means import ALL versions @@ -1211,7 +1212,7 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix) QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, int vmaj, int vmin, - QQmlScript::Import::Type type, + QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence) { Q_ASSERT(nameSpace); @@ -1224,7 +1225,7 @@ QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImport import->url = url; import->majversion = vmaj; import->minversion = vmin; - import->isLibrary = (type == QQmlScript::Import::Library); + import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary); if (lowPrecedence) nameSpace->imports.append(import); @@ -1245,7 +1246,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre QQmlImportNamespace *nameSpace = importNamespace(prefix); Q_ASSERT(nameSpace); - QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QQmlScript::Import::Library, errors); + QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors); Q_ASSERT(inserted); if (!incomplete) { @@ -1375,7 +1376,7 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix if (!url.endsWith(Slash) && !url.endsWith(Backslash)) url += Slash; - QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QQmlScript::Import::File, errors, isImplicitImport); + QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport); Q_ASSERT(inserted); if (!incomplete && !qmldirIdentifier.isEmpty()) { @@ -1578,8 +1579,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) QQmlImportDatabase::~QQmlImportDatabase() { - qDeleteAll(qmldirCache); - qmldirCache.clear(); + clearDirCache(); } /*! @@ -1814,7 +1814,7 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths) fileImportPath = paths; // Our existing cached paths may have been invalidated - qmldirCache.clear(); + clearDirCache(); } /*! @@ -2024,4 +2024,20 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr #endif } +void QQmlImportDatabase::clearDirCache() +{ + QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.begin(); + while (itr != qmldirCache.end()) { + QmldirCache *cache = *itr; + do { + QmldirCache *nextCache = cache->next; + delete cache; + cache = nextCache; + } while (cache); + + ++itr; + } + qmldirCache.clear(); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index b19e777852..3c9452963c 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -47,8 +47,8 @@ #include <QtCore/qset.h> #include <QtCore/qstringlist.h> #include <private/qqmldirparser_p.h> -#include <private/qqmlscript_p.h> #include <private/qqmlmetatype_p.h> +#include <private/qhashedstring_p.h> // // W A R N I N G @@ -174,6 +174,7 @@ private: const QString &typeNamespace, QList<QQmlError> *errors); bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, QList<QQmlError> *errors); + void clearDirCache(); struct QmldirCache { int versionMajor; diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 4c9c99f1f6..4cdeb19719 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -169,6 +169,20 @@ void QQmlIncubatorPrivate::clear() nextWaitingFor.remove(); waitingOnMe = 0; } + + // if we're waiting on any incubators then they should be cleared too. + while (waitingFor.first()) { + QQmlIncubator * i = static_cast<QQmlIncubatorPrivate*>(waitingFor.first())->q; + if (i) + i->clear(); + } + + bool guardOk = vmeGuard.isOK(); + + vmeGuard.clear(); + if (creator && guardOk) + creator->clear(); + creator.reset(0); } /*! @@ -393,7 +407,7 @@ void QQmlIncubationController::incubateFor(int msecs) /*! Incubate objects while the bool pointed to by \a flag is true, or until there are no -more objects to incubate, or up to msecs if msecs is not zero. +more objects to incubate, or up to \a msecs if \a msecs is not zero. Generally this method is used in conjunction with a thread or a UNIX signal that sets the bool pointed to by \a flag to false when it wants incubation to be interrupted. @@ -562,20 +576,6 @@ void QQmlIncubator::clear() d->clear(); - // if we're waiting on any incubators then they should be cleared too. - while (d->waitingFor.first()) { - QQmlIncubator * i = static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q; - if (i) - i->clear(); - } - - bool guardOk = d->vmeGuard.isOK(); - - d->vmeGuard.clear(); - if (d->creator && guardOk) - d->creator->clear(); - d->creator.reset(0); - Q_ASSERT(d->compiledData == 0); Q_ASSERT(d->waitingOnMe.data() == 0); Q_ASSERT(d->waitingFor.isEmpty()); @@ -687,7 +687,7 @@ void QQmlIncubator::statusChanged(Status status) } /*! -Called after the object is first created, but before property bindings are +Called after the \a object is first created, but before property bindings are evaluated and, if applicable, QQmlParserStatus::componentComplete() is called. This is equivalent to the point between QQmlComponent::beginCreate() and QQmlComponent::endCreate(), and can be used to assign initial values diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index b233b6e98c..560a4c8afd 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -218,7 +218,6 @@ void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n) } /*! \internal - \reimp \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 0d60fee5d0..fd50e2dbbc 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -129,13 +129,21 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper QV4::ExecutionEngine *e = m->engine(); QmlListWrapper *w = m->as<QmlListWrapper>(); - if (!w) + if (!w) { + if (hasProperty) + *hasProperty = false; return e->currentContext()->throwTypeError(); + } quint32 count = w->property.count ? w->property.count(&w->property) : 0; - if (index < count && w->property.at) + if (index < count && w->property.at) { + if (hasProperty) + *hasProperty = true; return QV4::QObjectWrapper::wrap(e, w->property.at(&w->property, index)); + } + if (hasProperty) + *hasProperty = false; return Primitive::undefinedValue().asReturnedValue(); } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index fc9e2fc42a..178280b27c 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -290,8 +290,11 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte tm = r->locale.toTime(dateString, enumFormat); } - QDateTime dt = QDateTime::currentDateTime(); - dt.setTime(tm); + QDateTime dt; + if (tm.isValid()) { + dt = QDateTime::currentDateTime(); + dt.setTime(tm); + } return QV4::Encode(engine->newDateObject(dt)); } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 90d3ca3308..42f67f3345 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -106,6 +106,7 @@ struct QQmlMetaTypeData QBitArray lists; QList<QQmlPrivate::AutoParentFunction> parentFunctions; + QQmlPrivate::QmlUnitCacheLookupFunction lookupCachedQmlUnit; QSet<QString> protectedNamespaces; @@ -142,6 +143,7 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v) } QQmlMetaTypeData::QQmlMetaTypeData() + : lookupCachedQmlUnit(0) { } @@ -1344,6 +1346,15 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) return index; } +int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) +{ + if (hookRegistration.version > 0) + qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); + QWriteLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + data->lookupCachedQmlUnit = hookRegistration.lookupCachedQmlUnit; + return 0; +} /* This method is "over generalized" to allow us to (potentially) register more types of things in @@ -1363,6 +1374,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); } else if (type == CompositeSingletonRegistration) { return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); + } else if (type == QmlUnitCacheHookRegistration) { + return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data)); } return -1; } @@ -1865,26 +1878,13 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() return retn; } -int QQmlMetaType::QQuickAnchorLineMetaTypeId() +const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri) { - static int id = 0; - if (!id) { - id = QMetaType::type("QQuickAnchorLine"); - } - return id; -} - -QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0; - -void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun) -{ - anchorLineCompareFunction = fun; -} - -bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2) -{ - Q_ASSERT(anchorLineCompareFunction != 0); - return anchorLineCompareFunction(p1, p2); + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + if (data->lookupCachedQmlUnit) + return data->lookupCachedQmlUnit(uri); + return 0; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 019e6b8821..715ff80c46 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -120,10 +120,7 @@ public: static QList<QQmlPrivate::AutoParentFunction> parentFunctions(); - static int QQuickAnchorLineMetaTypeId(); - typedef bool (*CompareFunction)(const void *, const void *); - static void setQQuickAnchorLineCompareFunction(CompareFunction); - static bool QQuickAnchorLineCompare(const void *p1, const void *p2); + static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(const QUrl &uri); static bool namespaceContainsRegistrations(const QString &); @@ -133,9 +130,6 @@ public: static QStringList typeRegistrationFailures(); static QReadWriteLock *typeRegistrationLock(); - -private: - static CompareFunction anchorLineCompareFunction; }; struct QQmlMetaTypeData; @@ -240,6 +234,7 @@ private: friend int registerInterface(const QQmlPrivate::RegisterInterface &); friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &); friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &); + friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &); friend Q_QML_EXPORT void qmlClearTypeRegistrations(); QQmlType(int, const QQmlPrivate::RegisterInterface &); QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 50fe5861a6..2ebf90c9be 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -85,7 +85,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile , compiledData(compiledData) , resolvedTypes(compiledData->resolvedTypes) , propertyCaches(compiledData->propertyCaches) - , vmeMetaObjectData(compiledData->datas) + , vmeMetaObjectData(compiledData->metaObjects) , activeVMEDataForRootContext(activeVMEDataForRootContext) { init(parentContext); @@ -98,7 +98,10 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount); sharedState->creationContext = creationContext; sharedState->rootContext = 0; - sharedState->profiler.profiler = QQmlEnginePrivate::get(engine)->profiler; + + QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler; + Q_QML_PROFILE_IF_ENABLED(profiler, + sharedState->profiler.init(profiler, compiledData->totalParserStatusCount)); } QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState) @@ -106,7 +109,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile , compiledData(compiledData) , resolvedTypes(compiledData->resolvedTypes) , propertyCaches(compiledData->propertyCaches) - , vmeMetaObjectData(compiledData->datas) + , vmeMetaObjectData(compiledData->metaObjects) , activeVMEDataForRootContext(0) { init(parentContext); @@ -213,7 +216,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context->importedScripts = sharedState->creationContext->importedScripts; } - QObject *instance = createInstance(objectToCreate, parent); + QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true); if (instance) { QQmlData *ddata = QQmlData::get(instance); Q_ASSERT(ddata); @@ -221,12 +224,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI ddata->compiledData->release(); ddata->compiledData = compiledData; ddata->compiledData->addref(); - - context->contextObject = instance; } - Q_QML_VME_PROFILE(sharedState->profiler, stop()); - phase = CreatingObjectsPhase2; if (interrupt && interrupt->shouldInterrupt()) @@ -241,6 +240,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) { QQmlData *declarativeData = QQmlData::get(instance); context = declarativeData->deferredData->context; + sharedState->rootContext = context; const int objectIndex = declarativeData->deferredData->deferredIdx; const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); @@ -704,7 +704,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (!name.isEmpty()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) - property = PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context); + property = QmlIR::PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context); else property = _propertyCache->property(name, _qobject, context); } else @@ -745,7 +745,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4 // ### resolve this at compile time if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = QQmlBinding::Invalid; + ss.d.data()->bindingId = binding->value.compiledScriptIndex; 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; @@ -820,7 +820,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4 QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; QV4::Scope scope(_qmlContext); - QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction, /*createProto*/ false)); + QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(_qmlContext, runtimeFunction, /*createProto*/ false)); if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex); @@ -998,7 +998,7 @@ void QQmlObjectCreator::setupFunctions() if (!property->isVMEFunction()) continue; - function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction); + function = QV4::FunctionObject::createScriptFunction(_qmlContext, runtimeFunction); _vmeMetaObject->setVmeMethod(property->coreIndex, function); } } @@ -1013,8 +1013,9 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, errors << error; } -QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) +QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) { + QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler); ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); bool isComponent = false; @@ -1024,21 +1025,23 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) QQmlParserStatus *parserStatus = 0; bool installPropertyCache = true; + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); if (compiledData->isComponent(index)) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"), + context->url, obj->location.line, obj->location.column)); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); } else { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; QQmlType *type = typeRef->type; if (type) { - Q_QML_VME_PROFILE(sharedState->profiler, start(type->qmlTypeName(), context->url, obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(), + context->url, obj->location.line, obj->location.column)); instance = type->create(); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1060,23 +1063,23 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->component); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name, + context->url, obj->location.line, obj->location.column)); if (typeRef->component->qmlUnit->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } - Q_QML_VME_PROFILE(sharedState->profiler, startBackground(typeRef->component->name)); + QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data()); instance = subCreator.create(); - Q_QML_VME_PROFILE(sharedState->profiler, foreground(context->url, obj->location.line, obj->location.column)); if (!instance) { errors += subCreator.errors; return 0; } } - // ### use no-event variant if (parent) - instance->setParent(parent); + QQml_setParent_noEvent(instance, parent); ddata = QQmlData::get(instance, /*create*/true); ddata->lineNumber = obj->location.line; @@ -1102,6 +1105,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) if (parserStatus) { parserStatus->classBegin(); + // push() the profiler state here, together with the parserStatus, as we'll pop() them + // together, too. + Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler)); sharedState->allParserStatusCallbacks.push(parserStatus); parserStatus->d = &sharedState->allParserStatusCallbacks.top(); } @@ -1110,11 +1116,16 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) if (idEntry != objectIndexToId.constEnd()) context->setIdProperty(idEntry.value(), instance); + // Register the context object in the context early on in order for pending binding + // initialization to find it available. + if (isContextObject) + context->contextObject = instance; + QBitArray bindingsToSkip; if (customParser) { QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index); if (entry != compiledData->customParserData.constEnd()) { - customParser->setCustomData(instance, entry->compilationArtifact); + customParser->setCustomData(instance, entry->compilationArtifact, compiledData); bindingsToSkip = entry->bindings; } } @@ -1122,7 +1133,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) if (isComponent) return instance; - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); Q_ASSERT(!cache.isNull()); if (installPropertyCache) { if (ddata->propertyCache) @@ -1183,7 +1194,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later QQmlTrace trace("VME Component Complete"); while (!sharedState->allParserStatusCallbacks.isEmpty()) { - Q_QML_VME_PROFILE(sharedState->profiler, pop()); + QQmlObjectCompletionProfiler profiler(&sharedState->profiler); QQmlParserStatus *status = sharedState->allParserStatusCallbacks.pop(); if (status && status->d) { @@ -1194,7 +1205,6 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; } - Q_QML_VME_PROFILE(sharedState->profiler, clear()); } { @@ -1243,20 +1253,12 @@ void QQmlObjectCreator::clear() while (!sharedState->allCreatedObjects.isEmpty()) delete sharedState->allCreatedObjects.pop(); - // If profiling is switched off during a VME run and then switched back on - // before or during the next run background ranges from the first run will - // be reported in the second run because we don't clear() here. We accept - // that as the collected data will be incomplete anyway and because not - // calling clear() here is benefitial for the non-profiling case. - Q_QML_VME_PROFILE(sharedState->profiler, clear(true)); - phase = Done; } bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - Q_QML_VME_PROFILE(sharedState->profiler, push()); QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); @@ -1270,7 +1272,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QV4::Scope valueScope(v4); QV4::ScopedValue scopeObjectProtector(valueScope); - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); QQmlVMEMetaObject *vmeMetaObject = 0; const QByteArray data = vmeMetaObjectData.value(index); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 9fd52a9f48..379a3b2970 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -96,7 +96,7 @@ private: void init(QQmlContextData *parentContext); - QObject *createInstance(int index, QObject *parent = 0); + QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false); bool populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h index 4e611f82b1..92b320ec0c 100644 --- a/src/qml/qml/qqmlparserstatus.h +++ b/src/qml/qml/qqmlparserstatus.h @@ -58,7 +58,6 @@ public: virtual void componentComplete()=0; private: - friend class QQmlVME; friend class QQmlComponent; friend class QQmlComponentPrivate; friend class QQmlEnginePrivate; diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index 04862379be..8ee4a542de 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -60,23 +60,27 @@ QQmlPlatform::~QQmlPlatform() QString QQmlPlatform::os() { #if defined(Q_OS_ANDROID) - return QLatin1String("android"); + return QStringLiteral("android"); #elif defined(Q_OS_BLACKBERRY) - return QLatin1String("blackberry"); + return QStringLiteral("blackberry"); #elif defined(Q_OS_IOS) - return QLatin1String("ios"); + return QStringLiteral("ios"); #elif defined(Q_OS_MAC) - return QLatin1String("osx"); + return QStringLiteral("osx"); #elif defined(Q_OS_WINCE) - return QLatin1String("wince"); + return QStringLiteral("wince"); +#elif defined(Q_OS_WINPHONE) + return QStringLiteral("winphone"); +#elif defined(Q_OS_WINRT) + return QStringLiteral("winrt"); #elif defined(Q_OS_WIN) - return QLatin1String("windows"); + return QStringLiteral("windows"); #elif defined(Q_OS_LINUX) - return QLatin1String("linux"); + return QStringLiteral("linux"); #elif defined(Q_OS_UNIX) - return QLatin1String("unix"); + return QStringLiteral("unix"); #else - return QLatin1String("unknown"); + return QStringLiteral("unknown"); #endif } diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 90e7961e6b..5460c99f1d 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -61,6 +61,22 @@ QT_BEGIN_NAMESPACE +namespace QQmlPrivate { +struct CachedQmlUnit; +} + +namespace QV4 { +struct ExecutionEngine; +namespace CompiledData { +struct QmlUnit; +struct CompilationUnit; +} +typedef CompiledData::CompilationUnit *(*CompilationUnitFactoryFunction)(); +} +namespace QmlIR { +struct Document; +typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *); +} typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *); @@ -268,13 +284,26 @@ namespace QQmlPrivate const char *typeName; }; + struct CachedQmlUnit { + const QV4::CompiledData::QmlUnit *qmlData; + QV4::CompilationUnitFactoryFunction createCompilationUnit; + QmlIR::IRLoaderFunction loadIR; + }; + + typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url); + struct RegisterQmlUnitCacheHook { + int version; + QmlUnitCacheLookupFunction lookupCachedQmlUnit; + }; + enum RegistrationType { TypeRegistration = 0, InterfaceRegistration = 1, AutoParentRegistration = 2, SingletonRegistration = 3, CompositeRegistration = 4, - CompositeSingletonRegistration = 5 + CompositeSingletonRegistration = 5, + QmlUnitCacheHookRegistration = 6 }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 0bbcafda54..1075b53c5e 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1403,6 +1403,12 @@ bool QQmlPropertyPrivate::write(QObject *object, v = value; if (v.convert(propertyType)) { ok = true; + } else if (v.isValid() && value.isNull()) { + // For historical reasons converting a null QVariant to another type will do the trick + // but return false anyway. This is caught with the above condition and considered a + // successful conversion. + Q_ASSERT(v.userType() == propertyType); + ok = true; } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) { QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType); if (con) { diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp deleted file mode 100644 index cf56d5701d..0000000000 --- a/src/qml/qml/qqmlscript.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlscript_p.h" - -#include <private/qqmljsengine_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsmemorypool_p.h> -#include <private/qqmljsastvisitor_p.h> -#include <private/qqmljsast_p.h> - -#include <QStack> -#include <QStringList> -#include <QCoreApplication> -#include <QtDebug> - -QT_BEGIN_NAMESPACE - -using namespace QQmlJS; -using namespace QQmlScript; - -static void replaceWithSpace(QString &str, int idx, int n) -{ - QChar *data = str.data() + idx; - const QChar space(QLatin1Char(' ')); - for (int ii = 0; ii < n; ++ii) - *data++ = space; -} - -static QQmlScript::LocationSpan -locationFromLexer(const QQmlJS::Lexer &lex, int startLine, int startColumn, int startOffset) -{ - QQmlScript::LocationSpan l; - - l.start.line = startLine; l.start.column = startColumn; - l.end.line = lex.tokenEndLine(); l.end.column = lex.tokenEndColumn(); - l.range.offset = startOffset; - l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset; - - return l; -} - -/* -Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas -are: - library -*/ -QQmlScript::Object::ScriptBlock::Pragmas QQmlScript::Parser::extractPragmas(QString &script) -{ - QQmlScript::Object::ScriptBlock::Pragmas rv = QQmlScript::Object::ScriptBlock::None; - - const QString pragma(QLatin1String("pragma")); - const QString library(QLatin1String("library")); - - QQmlJS::Lexer l(0); - l.setCode(script, 0); - - int token = l.lex(); - - while (true) { - if (token != QQmlJSGrammar::T_DOT) - return rv; - - int startOffset = l.tokenOffset(); - int startLine = l.tokenStartLine(); - - token = l.lex(); - - if (token != QQmlJSGrammar::T_PRAGMA || - l.tokenStartLine() != startLine || - script.mid(l.tokenOffset(), l.tokenLength()) != pragma) - return rv; - - token = l.lex(); - - if (token != QQmlJSGrammar::T_IDENTIFIER || - l.tokenStartLine() != startLine) - return rv; - - QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); - int endOffset = l.tokenLength() + l.tokenOffset(); - - token = l.lex(); - if (l.tokenStartLine() == startLine) - return rv; - - if (pragmaValue == library) { - rv |= QQmlScript::Object::ScriptBlock::Shared; - replaceWithSpace(script, startOffset, endOffset - startOffset); - } else { - return rv; - } - } - return rv; -} - -#define CHECK_LINE if (l.tokenStartLine() != startLine) return rv; -#define CHECK_TOKEN(t) if (token != QQmlJSGrammar:: t) return rv; - -static const int uriTokens[] = { - QQmlJSGrammar::T_IDENTIFIER, - QQmlJSGrammar::T_PROPERTY, - QQmlJSGrammar::T_SIGNAL, - QQmlJSGrammar::T_READONLY, - QQmlJSGrammar::T_ON, - QQmlJSGrammar::T_BREAK, - QQmlJSGrammar::T_CASE, - QQmlJSGrammar::T_CATCH, - QQmlJSGrammar::T_CONTINUE, - QQmlJSGrammar::T_DEFAULT, - QQmlJSGrammar::T_DELETE, - QQmlJSGrammar::T_DO, - QQmlJSGrammar::T_ELSE, - QQmlJSGrammar::T_FALSE, - QQmlJSGrammar::T_FINALLY, - QQmlJSGrammar::T_FOR, - QQmlJSGrammar::T_FUNCTION, - QQmlJSGrammar::T_IF, - QQmlJSGrammar::T_IN, - QQmlJSGrammar::T_INSTANCEOF, - QQmlJSGrammar::T_NEW, - QQmlJSGrammar::T_NULL, - QQmlJSGrammar::T_RETURN, - QQmlJSGrammar::T_SWITCH, - QQmlJSGrammar::T_THIS, - QQmlJSGrammar::T_THROW, - QQmlJSGrammar::T_TRUE, - QQmlJSGrammar::T_TRY, - QQmlJSGrammar::T_TYPEOF, - QQmlJSGrammar::T_VAR, - QQmlJSGrammar::T_VOID, - QQmlJSGrammar::T_WHILE, - QQmlJSGrammar::T_CONST, - QQmlJSGrammar::T_DEBUGGER, - QQmlJSGrammar::T_RESERVED_WORD, - QQmlJSGrammar::T_WITH, - - QQmlJSGrammar::EOF_SYMBOL -}; -static inline bool isUriToken(int token) -{ - const int *current = uriTokens; - while (*current != QQmlJSGrammar::EOF_SYMBOL) { - if (*current == token) - return true; - ++current; - } - return false; -} - -static void extractVersion(QStringRef string, int *maj, int *min) -{ - *maj = -1; *min = -1; - - if (!string.isEmpty()) { - - int dot = string.indexOf(QLatin1Char('.')); - - if (dot < 0) { - *maj = string.toInt(); - *min = 0; - } else { - *maj = string.left(dot).toInt(); - *min = string.mid(dot + 1).toInt(); - } - } -} - -QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QString &script, QQmlError *error) -{ - Q_ASSERT(error); - - JavaScriptMetaData rv; - - QQmlScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas; - - const QString js(QLatin1String(".js")); - const QString library(QLatin1String("library")); - - QQmlJS::Lexer l(0); - l.setCode(script, 0); - - int token = l.lex(); - - while (true) { - if (token != QQmlJSGrammar::T_DOT) - return rv; - - int startOffset = l.tokenOffset(); - int startLine = l.tokenStartLine(); - int startColumn = l.tokenStartColumn(); - - QQmlError importError; - importError.setLine(startLine + 1); // 0-based, adjust to be 1-based - - token = l.lex(); - - CHECK_LINE; - - if (token == QQmlJSGrammar::T_IMPORT) { - - // .import <URI> <Version> as <Identifier> - // .import <file.js> as <Identifier> - - token = l.lex(); - - CHECK_LINE; - - if (token == QQmlJSGrammar::T_STRING_LITERAL) { - - QString file = l.tokenText(); - - if (!file.endsWith(js)) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Imported file must be a script")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - bool invalidImport = false; - - token = l.lex(); - - if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) { - invalidImport = true; - } else { - token = l.lex(); - - if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine)) - invalidImport = true; - } - - - if (invalidImport) { - importError.setDescription(QCoreApplication::translate("QQmlParser","File import requires a qualifier")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - int endOffset = l.tokenLength() + l.tokenOffset(); - - QString importId = script.mid(l.tokenOffset(), l.tokenLength()); - - QQmlScript::LocationSpan location = - locationFromLexer(l, startLine, startColumn, startOffset); - - token = l.lex(); - - if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - replaceWithSpace(script, startOffset, endOffset - startOffset); - - Import import; - import.type = Import::Script; - import.uri = file; - import.qualifier = importId; - import.location = location; - - rv.imports << import; - } else { - // URI - QString uri; - - while (true) { - if (!isUriToken(token)) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid module URI")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - uri.append(l.tokenText()); - - token = l.lex(); - CHECK_LINE; - if (token != QQmlJSGrammar::T_DOT) - break; - - uri.append(QLatin1Char('.')); - - token = l.lex(); - CHECK_LINE; - } - - if (token != QQmlJSGrammar::T_NUMERIC_LITERAL) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Module import requires a version")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - int vmaj, vmin; - extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()), - &vmaj, &vmin); - - bool invalidImport = false; - - token = l.lex(); - - if ((token != QQmlJSGrammar::T_AS) || (l.tokenStartLine() != startLine)) { - invalidImport = true; - } else { - token = l.lex(); - - if ((token != QQmlJSGrammar::T_IDENTIFIER) || (l.tokenStartLine() != startLine)) - invalidImport = true; - } - - - if (invalidImport) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Module import requires a qualifier")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - int endOffset = l.tokenLength() + l.tokenOffset(); - - QString importId = script.mid(l.tokenOffset(), l.tokenLength()); - - QQmlScript::LocationSpan location = - locationFromLexer(l, startLine, startColumn, startOffset); - - token = l.lex(); - - if (!importId.at(0).isUpper() || (l.tokenStartLine() == startLine)) { - importError.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier")); - importError.setColumn(l.tokenStartColumn()); - *error = importError; - return rv; - } - - replaceWithSpace(script, startOffset, endOffset - startOffset); - - Import import; - import.type = Import::Library; - import.uri = uri; - import.majorVersion = vmaj; - import.minorVersion = vmin; - import.qualifier = importId; - import.location = location; - - rv.imports << import; - } - } else if (token == QQmlJSGrammar::T_PRAGMA) { - token = l.lex(); - - CHECK_TOKEN(T_IDENTIFIER); - CHECK_LINE; - - QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); - int endOffset = l.tokenLength() + l.tokenOffset(); - - if (pragmaValue == library) { - pragmas |= QQmlScript::Object::ScriptBlock::Shared; - replaceWithSpace(script, startOffset, endOffset - startOffset); - } else { - return rv; - } - - token = l.lex(); - if (l.tokenStartLine() == startLine) - return rv; - - } else { - return rv; - } - } - return rv; -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h deleted file mode 100644 index 15446c089f..0000000000 --- a/src/qml/qml/qqmlscript_p.h +++ /dev/null @@ -1,180 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QQMLSCRIPT_P_H -#define QQMLSCRIPT_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 <QtQml/qqmlerror.h> - -#include <private/qfieldlist_p.h> -#include <private/qhashfield_p.h> -#include <private/qqmlpool_p.h> -#include <private/qqmlpropertycache_p.h> - -#include <QtCore/QList> -#include <QtCore/QUrl> - -QT_BEGIN_NAMESPACE - - -class QByteArray; -class QQmlPropertyCache; -namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; class FunctionDeclaration; } } - -namespace QQmlScript { - -struct Location -{ - Location() : line(0), column(0) {} - quint16 line; - quint16 column; - - inline bool operator<(const Location &other) { - return line < other.line || - (line == other.line && column < other.column); - } -}; - -struct LocationRange -{ - LocationRange() : offset(0), length(0) {} - quint32 offset; - quint32 length; -}; - -struct LocationSpan -{ - Location start; - Location end; - LocationRange range; - - bool operator<(LocationSpan &o) const { - return (start.line < o.start.line) || - (start.line == o.start.line && start.column < o.start.column); - } -}; - -class Import -{ -public: - Import() : type(Library), majorVersion(-1), minorVersion(-1) {} - - enum Type { Library, File, Script }; - Type type; - - QString uri; - QString qualifier; - - int majorVersion; - int minorVersion; - - QQmlScript::LocationSpan location; -}; - -class Pragma -{ -public: - Pragma() : type(Singleton) {} - - enum Type { Singleton }; - Type type; - - QQmlScript::LocationSpan location; -}; - -class Object; -class TypeReference : public QQmlPool::Class -{ -public: - // type as it has been referenced in Qml - QString name; -}; - -class Object : public QQmlPool::Class -{ -public: - // Script blocks that were nested under this object - struct ScriptBlock { - enum Pragma { - None = 0x00000000, - Shared = 0x00000001 - }; - Q_DECLARE_FLAGS(Pragmas, Pragma) - - QString code; - QString file; - Pragmas pragmas; - }; -}; - -class Q_QML_PRIVATE_EXPORT Parser -{ -public: - class JavaScriptMetaData { - public: - JavaScriptMetaData() - : pragmas(QQmlScript::Object::ScriptBlock::None) {} - - QQmlScript::Object::ScriptBlock::Pragmas pragmas; - QList<Import> imports; - }; - - static QQmlScript::Object::ScriptBlock::Pragmas extractPragmas(QString &); - static JavaScriptMetaData extractMetaData(QString &, QQmlError *error); -}; - -} - -Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlScript::Object::ScriptBlock::Pragmas) - -QT_END_NAMESPACE - -#endif // QQMLSCRIPT_P_H diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h index 9817fdc92c..2c10df6efc 100644 --- a/src/qml/qml/qqmlscriptstring.h +++ b/src/qml/qml/qqmlscriptstring.h @@ -77,7 +77,6 @@ private: friend class QQmlObjectCreator; friend class QQmlScriptStringPrivate; - friend class QQmlVME; friend class QQmlExpression; friend class QQmlBinding; }; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 5c48304b56..7fc08bd114 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -51,7 +51,6 @@ #include <private/qqmlcomponent_p.h> #include <private/qqmlprofiler_p.h> #include <private/qqmlmemoryprofiler_p.h> -#include <private/qqmlcodegenerator_p.h> #include <private/qqmltypecompiler_p.h> #include <QtCore/qdir.h> @@ -148,6 +147,7 @@ public: void loadAsync(QQmlDataBlob *b); void loadWithStaticData(QQmlDataBlob *b, const QByteArray &); void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &); + void loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit); void callCompleted(QQmlDataBlob *b); void callDownloadProgressChanged(QQmlDataBlob *b, qreal p); void initializeEngine(QQmlExtensionInterface *, const char *); @@ -158,6 +158,7 @@ protected: private: void loadThread(QQmlDataBlob *b); void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &); + void loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit); void callCompletedMain(QQmlDataBlob *b); void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p); void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri); @@ -778,6 +779,12 @@ void QQmlDataLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteA postMethodToThread(&This::loadWithStaticDataThread, b, d); } +void QQmlDataLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit) +{ + b->addref(); + callMethodInThread(&This::loadWithCachedUnitThread, b, unit); +} + void QQmlDataLoaderThread::callCompleted(QQmlDataBlob *b) { b->addref(); @@ -816,6 +823,12 @@ void QQmlDataLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByte b->release(); } +void QQmlDataLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QQmlPrivate::CachedQmlUnit *unit) +{ + m_loader->loadWithCachedUnitThread(b, unit); + b->release(); +} + void QQmlDataLoaderThread::callCompletedMain(QQmlDataBlob *b) { QML_MEMORY_SCOPE_URL(b->url()); @@ -966,6 +979,28 @@ void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da } } +void QQmlDataLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) +{ +#ifdef DATABLOB_DEBUG + qWarning("QQmlDataLoader::loadWithUnitFcatory(%s, data): %s thread", qPrintable(blob->m_url.toString()), + m_thread->isThisThread()?"Compile":"Engine"); +#endif + + blob->startLoading(this); + + if (m_thread->isThisThread()) { + unlock(); + loadWithCachedUnitThread(blob, unit); + lock(); + } else { + unlock(); + m_thread->loadWithCachedUnit(blob, unit); + lock(); + if (!blob->isCompleteOrError()) + blob->m_data.setIsAsync(true); + } +} + void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data) { ASSERT_LOADTHREAD(); @@ -973,6 +1008,13 @@ void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArr setData(blob, data); } +void QQmlDataLoader::loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) +{ + ASSERT_LOADTHREAD(); + + setCachedUnit(blob, unit); +} + void QQmlDataLoader::loadThread(QQmlDataBlob *blob) { ASSERT_LOADTHREAD(); @@ -1166,6 +1208,24 @@ void QQmlDataLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) blob->tryDone(); } +void QQmlDataLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) +{ + QML_MEMORY_SCOPE_URL(blob->url()); + blob->m_inCallback = true; + + blob->initializeFromCachedUnit(unit); + + if (!blob->isError() && !blob->isWaiting()) + blob->allDependenciesDone(); + + if (blob->status() != QQmlDataBlob::Error) + blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies); + + blob->m_inCallback = false; + + blob->tryDone(); +} + void QQmlDataLoader::shutdownThread() { if (!m_thread->isShutdown()) @@ -1173,7 +1233,7 @@ void QQmlDataLoader::shutdownThread() } QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader) - : QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader), m_isSingleton(false) + : QQmlDataBlob(url, type), m_typeLoader(loader), m_importCache(loader), m_isSingleton(false) { } @@ -1183,7 +1243,7 @@ QQmlTypeLoader::Blob::~Blob() m_qmldirs.at(ii)->release(); } -bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors) +bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors) { QQmlQmldirData *data = typeLoader()->getQmldir(url); @@ -1204,17 +1264,17 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QQmlScript::Import return true; } -bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors) +bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { QString qmldirIdentifier = data->url().toString(); QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1); typeLoader()->setQmldirContent(qmldirIdentifier, data->content()); - if (!m_imports.updateQmldirContent(typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors)) + if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), stringAt(import->uriIndex), stringAt(import->qualifierIndex), qmldirIdentifier, qmldirUrl, errors)) return false; - QHash<const QQmlScript::Import *, int>::iterator it = m_unresolvedImports.find(import); + QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import); if (it != m_unresolvedImports.end()) { *it = data->priority(); } @@ -1222,7 +1282,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript:: // Release this reference at destruction m_qmldirs << data; - if (!import->qualifier.isEmpty()) { + const QString &importQualifier = stringAt(import->qualifierIndex); + if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier, qmldirUrl); @@ -1231,43 +1292,45 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QQmlScript:: QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); addDependency(blob); - scriptImported(blob, import->location.start, script.nameSpace, import->qualifier); + scriptImported(blob, import->location, script.nameSpace, importQualifier); } } return true; } -bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQmlError> *errors) +bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_ASSERT(errors); QQmlImportDatabase *importDatabase = typeLoader()->importDatabase(); - if (import.type == QQmlScript::Import::Script) { - QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri)); + const QString &importUri = stringAt(import->uriIndex); + const QString &importQualifier = stringAt(import->qualifierIndex); + if (import->type == QV4::CompiledData::Import::ImportScript) { + QUrl scriptUrl = finalUrl().resolved(QUrl(importUri)); QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); addDependency(blob); - scriptImported(blob, import.location.start, import.qualifier, QString()); - } else if (import.type == QQmlScript::Import::Library) { + scriptImported(blob, import->location, importQualifier, QString()); + } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; - if (QQmlMetaType::isLockedModule(import.uri, import.majorVersion)) { + if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks - if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion, - import.minorVersion, QString(), QString(), false, errors)) + if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, + import->minorVersion, QString(), QString(), false, errors)) return false; - } else if (m_imports.locateQmldir(importDatabase, import.uri, import.majorVersion, import.minorVersion, + } else if (m_importCache.locateQmldir(importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import - if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion, - import.minorVersion, qmldirFilePath, qmldirUrl, false, errors)) + if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, + import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; - if (!import.qualifier.isEmpty()) { + if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath, qmldirUrl); @@ -1276,34 +1339,34 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); addDependency(blob); - scriptImported(blob, import.location.start, script.nameSpace, import.qualifier); + scriptImported(blob, import->location, script.nameSpace, importQualifier); } } } else { // Is this a module? - if (QQmlMetaType::isAnyModule(import.uri)) { - if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion, - import.minorVersion, QString(), QString(), false, errors)) + if (QQmlMetaType::isAnyModule(importUri)) { + if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, + import->minorVersion, QString(), QString(), false, errors)) return false; } else { // We haven't yet resolved this import - m_unresolvedImports.insert(&import, 0); + m_unresolvedImports.insert(import, 0); // Query any network import paths for this library QStringList remotePathList = importDatabase->importPathList(QQmlImportDatabase::Remote); if (!remotePathList.isEmpty()) { // Add this library and request the possible locations for it - if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion, - import.minorVersion, QString(), QString(), true, errors)) + if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, + import->minorVersion, QString(), QString(), true, errors)) return false; // Probe for all possible locations int priority = 0; for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { foreach (const QString &path, remotePathList) { - QString qmldirUrl = QQmlImports::completeQmldirPath(import.uri, path, import.majorVersion, import.minorVersion, + QString qmldirUrl = QQmlImports::completeQmldirPath(importUri, path, import->majorVersion, import->minorVersion, static_cast<QQmlImports::ImportVersion>(version)); - if (!fetchQmldir(QUrl(qmldirUrl), &import, ++priority, errors)) + if (!fetchQmldir(QUrl(qmldirUrl), import, ++priority, errors)) return false; } } @@ -1311,25 +1374,25 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm } } } else { - Q_ASSERT(import.type == QQmlScript::Import::File); + Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile); bool incomplete = false; QUrl qmldirUrl; - if (import.qualifier.isEmpty()) { - qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir"))); + if (importQualifier.isEmpty()) { + qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir"))); if (!QQmlImports::isLocal(qmldirUrl)) { // This is a remote file; the import is currently incomplete incomplete = true; } } - if (!m_imports.addFileImport(importDatabase, import.uri, import.qualifier, import.majorVersion, - import.minorVersion, incomplete, errors)) + if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion, + import->minorVersion, incomplete, errors)) return false; if (incomplete) { - if (!fetchQmldir(qmldirUrl, &import, 1, errors)) + if (!fetchQmldir(qmldirUrl, import, 1, errors)) return false; } } @@ -1337,11 +1400,11 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm return true; } -bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors) +bool QQmlTypeLoader::Blob::addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors) { Q_ASSERT(errors); - if (pragma.type == QQmlScript::Pragma::Singleton) { + if (pragma.type == QmlIR::Pragma::PragmaSingleton) { QUrl myUrl = finalUrl(); QQmlType *ret = QQmlMetaType::qmlType(myUrl, true); @@ -1349,8 +1412,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm QQmlError error; error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent.")); error.setUrl(myUrl); - error.setLine(pragma.location.start.line); - error.setColumn(pragma.location.start.column); + error.setLine(pragma.location.line); + error.setColumn(pragma.location.column); errors->prepend(error); return false; } @@ -1359,8 +1422,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm QQmlError error; error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName())); error.setUrl(myUrl); - error.setLine(pragma.location.start.line); - error.setColumn(pragma.location.start.column); + error.setLine(pragma.location.line); + error.setColumn(pragma.location.column); errors->prepend(error); return false; } @@ -1371,8 +1434,8 @@ bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQm QQmlError error; error.setDescription(QLatin1String("Invalid pragma")); error.setUrl(finalUrl()); - error.setLine(pragma.location.start.line); - error.setColumn(pragma.location.start.column); + error.setLine(pragma.location.line); + error.setColumn(pragma.location.column); errors->prepend(error); return false; } @@ -1395,15 +1458,15 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob) if (blob->type() == QQmlDataBlob::QmldirFile) { QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob); - const QQmlScript::Import *import = data->import(); + const QV4::CompiledData::Import *import = data->import(); QList<QQmlError> errors; if (!qmldirDataAvailable(data, &errors)) { Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); - error.setUrl(m_imports.baseUrl()); - error.setLine(import->location.start.line); - error.setColumn(import->location.start.column); + error.setUrl(m_importCache.baseUrl()); + error.setLine(import->location.line); + error.setColumn(import->location.column); errors.prepend(error); // put it back on the list after filling out information. setError(errors); } @@ -1414,7 +1477,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE { bool resolve = true; - const QQmlScript::Import *import = data->import(); + const QV4::CompiledData::Import *import = data->import(); data->setImport(0); int priority = data->priority(); @@ -1422,7 +1485,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE if (import) { // Do we need to resolve this import? - QHash<const QQmlScript::Import *, int>::iterator it = m_unresolvedImports.find(import); + QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import); if (it != m_unresolvedImports.end()) { resolve = (*it == 0) || (*it > priority); } @@ -1537,7 +1600,11 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) typeData = new QQmlTypeData(url, this); // TODO: if (compiledData == 0), is it safe to omit this insertion? m_typeCache.insert(url, typeData); - QQmlDataLoader::load(typeData, mode); + if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { + QQmlDataLoader::loadWithCachedUnit(typeData, cachedUnit); + } else { + QQmlDataLoader::load(typeData, mode); + } } typeData->addref(); @@ -1575,7 +1642,12 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url) if (!scriptBlob) { scriptBlob = new QQmlScriptBlob(url, this); m_scriptCache.insert(url, scriptBlob); - QQmlDataLoader::load(scriptBlob); + + if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) { + QQmlDataLoader::loadWithCachedUnit(scriptBlob, cachedUnit); + } else { + QQmlDataLoader::load(scriptBlob); + } } scriptBlob->addref(); @@ -1985,7 +2057,6 @@ QQmlTypeData::~QQmlTypeData() if (m_compiledData) m_compiledData->release(); - delete m_implicitImport; } const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const @@ -2045,7 +2116,7 @@ void QQmlTypeData::done() const TypeReference &type = *it; Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); if (type.typeData && type.typeData->isError()) { - QString typeName = parsedQML->jsGenerator.strings.at(it.key()); + QString typeName = m_document->stringAt(it.key()); QList<QQmlError> errors = type.typeData->errors(); QQmlError error; @@ -2092,7 +2163,8 @@ void QQmlTypeData::done() if (!isError()) compile(); - parsedQML.reset(); + m_document.reset(); + m_implicitImport = 0; } void QQmlTypeData::completed() @@ -2108,14 +2180,14 @@ bool QQmlTypeData::loadImplicitImport() { m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error) - m_imports.setBaseUrl(finalUrl(), finalUrlString()); + m_importCache.setBaseUrl(finalUrl(), finalUrlString()); QQmlImportDatabase *importDatabase = typeLoader()->importDatabase(); // For local urls, add an implicit import "." as most overridden lookup. // This will also trigger the loading of the qmldir and the import of any native // types from available plugins. QList<QQmlError> implicitImportErrors; - m_imports.addImplicitImport(importDatabase, &implicitImportErrors); + m_importCache.addImplicitImport(importDatabase, &implicitImportErrors); if (!implicitImportErrors.isEmpty()) { setError(implicitImportErrors); @@ -2133,14 +2205,37 @@ void QQmlTypeData::dataReceived(const Data &data) if (data.isFile()) preparseData = data.asFile()->metaData(QLatin1String("qml:preparse")); QQmlEngine *qmlEngine = typeLoader()->engine(); - parsedQML.reset(new QtQml::ParsedQML(QV8Engine::getV4(qmlEngine)->debugger != 0)); - QQmlCodeGenerator compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(code, finalUrl(), finalUrlString(), parsedQML.data())) { - setError(compiler.errors); + m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); + QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); + if (!compiler.generateFromQml(code, finalUrlString(), finalUrlString(), m_document.data())) { + QList<QQmlError> errors; + foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) { + QQmlError e; + e.setUrl(finalUrl()); + e.setLine(msg.loc.startLine); + e.setColumn(msg.loc.startColumn); + e.setDescription(msg.message); + errors << e; + } + setError(errors); return; } - m_imports.setBaseUrl(finalUrl(), finalUrlString()); + continueLoadFromIR(); +} + +void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) +{ + QQmlEngine *qmlEngine = typeLoader()->engine(); + m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); + unit->loadIR(m_document.data(), unit); + continueLoadFromIR(); +} + +void QQmlTypeData::continueLoadFromIR() +{ + m_document->collectTypeReferences(); + m_importCache.setBaseUrl(finalUrl(), finalUrlString()); // For remote URLs, we don't delay the loading of the implicit import // because the loading probably requires an asynchronous fetch of the @@ -2151,9 +2246,10 @@ void QQmlTypeData::dataReceived(const Data &data) if (!loadImplicitImport()) return; // This qmldir is for the implicit import - m_implicitImport = new QQmlScript::Import; - m_implicitImport->uri = QLatin1String("."); - m_implicitImport->qualifier = QString(); + QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool(); + m_implicitImport = pool->New<QV4::CompiledData::Import>(); + m_implicitImport->uriIndex = m_document->registerString(QLatin1String(".")); + m_implicitImport->qualifierIndex = 0; // empty string m_implicitImport->majorVersion = -1; m_implicitImport->minorVersion = -1; QList<QQmlError> errors; @@ -2167,62 +2263,21 @@ void QQmlTypeData::dataReceived(const Data &data) QList<QQmlError> errors; - // ### convert to use new data structure once old compiler is gone. - if (m_newImports.isEmpty()) { - m_newImports.reserve(parsedQML->imports.size()); - foreach (QV4::CompiledData::Import *i, parsedQML->imports) { - QQmlScript::Import import; - import.uri = parsedQML->stringAt(i->uriIndex); - import.qualifier = parsedQML->stringAt(i->qualifierIndex); - import.majorVersion = i->majorVersion; - import.minorVersion = i->minorVersion; - import.location.start.line = i->location.line; - import.location.start.column = i->location.column; - - switch (i->type) { - case QV4::CompiledData::Import::ImportFile: import.type = QQmlScript::Import::File; break; - case QV4::CompiledData::Import::ImportLibrary: import.type = QQmlScript::Import::Library; break; - case QV4::CompiledData::Import::ImportScript: import.type = QQmlScript::Import::Script; break; - default: break; - } - - - m_newImports << import; - } - } - - foreach (const QQmlScript::Import &import, m_newImports) { + foreach (const QV4::CompiledData::Import *import, m_document->imports) { if (!addImport(import, &errors)) { Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); - error.setUrl(m_imports.baseUrl()); - error.setLine(import.location.start.line); - error.setColumn(import.location.start.column); + error.setUrl(m_importCache.baseUrl()); + error.setLine(import->location.line); + error.setColumn(import->location.column); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return; } } - // ### convert to use new data structure once old compiler is gone. - if (m_newPragmas.isEmpty()) { - m_newPragmas.reserve(parsedQML->pragmas.size()); - foreach (QtQml::Pragma *p, parsedQML->pragmas) { - QQmlScript::Pragma pragma; - pragma.location.start.line = p->location.line; - pragma.location.start.column = p->location.column; - - switch (p->type) { - case QtQml::Pragma::PragmaSingleton: pragma.type = QQmlScript::Pragma::Singleton; break; - default: break; - } - - m_newPragmas << pragma; - } - } - - foreach (const QQmlScript::Pragma &pragma, m_newPragmas) { - if (!addPragma(pragma, &errors)) { + foreach (QmlIR::Pragma *pragma, m_document->pragmas) { + if (!addPragma(*pragma, &errors)) { Q_ASSERT(errors.size()); setError(errors); return; @@ -2235,16 +2290,16 @@ void QQmlTypeData::allDependenciesDone() if (!m_typesResolved) { // Check that all imports were resolved QList<QQmlError> errors; - QHash<const QQmlScript::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd(); + QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd(); for ( ; it != end; ++it) { if (*it == 0) { // This import was not resolved - foreach (const QQmlScript::Import *import, m_unresolvedImports.keys()) { + foreach (const QV4::CompiledData::Import *import, m_unresolvedImports.keys()) { QQmlError error; - error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri)); - error.setUrl(m_imports.baseUrl()); - error.setLine(import->location.start.line); - error.setColumn(import->location.start.column); + error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex))); + error.setUrl(m_importCache.baseUrl()); + error.setLine(import->location.line); + error.setColumn(import->location.column); errors.prepend(error); } } @@ -2267,6 +2322,11 @@ void QQmlTypeData::downloadProgressChanged(qreal p) } } +QString QQmlTypeData::stringAt(int index) const +{ + return m_document->jsGenerator.stringTable.stringForIndex(index); +} + void QQmlTypeData::compile() { Q_ASSERT(m_compiledData == 0); @@ -2277,7 +2337,7 @@ void QQmlTypeData::compile() QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, m_compiledData->name); - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, parsedQML.data()); + QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); if (!compiler.compile()) { setError(compiler.compilationErrors()); m_compiledData->release(); @@ -2288,7 +2348,7 @@ void QQmlTypeData::compile() void QQmlTypeData::resolveTypes() { // Add any imported scripts to our resolved set - foreach (const QQmlImports::ScriptReference &script, m_imports.resolvedScripts()) + foreach (const QQmlImports::ScriptReference &script, m_importCache.resolvedScripts()) { QQmlScriptBlob *blob = typeLoader()->getScript(script.location); addDependency(blob); @@ -2309,13 +2369,12 @@ void QQmlTypeData::resolveTypes() } // Lets handle resolved composite singleton types - foreach (const QQmlImports::CompositeSingletonReference &csRef, m_imports.resolvedCompositeSingletons()) { + foreach (const QQmlImports::CompositeSingletonReference &csRef, m_importCache.resolvedCompositeSingletons()) { TypeReference ref; - QQmlScript::TypeReference parserRef; - parserRef.name = csRef.typeName; + QString typeName = csRef.typeName; if (!csRef.prefix.isEmpty()) { - parserRef.name.prepend(csRef.prefix + QLatin1Char('.')); + typeName.prepend(csRef.prefix + QLatin1Char('.')); // Add a reference to the enclosing namespace m_namespaces.insert(csRef.prefix); } @@ -2323,7 +2382,7 @@ void QQmlTypeData::resolveTypes() int majorVersion = -1; int minorVersion = -1; - if (!resolveType(&parserRef, majorVersion, minorVersion, ref)) + if (!resolveType(typeName, majorVersion, minorVersion, ref)) return; if (ref.type->isCompositeSingleton()) { @@ -2335,15 +2394,7 @@ void QQmlTypeData::resolveTypes() } } - QV4::CompiledData::TypeReferenceMap typeReferences; - QStringList names; - if (parsedQML) { - typeReferences = parsedQML->typeReferences; - names = parsedQML->jsGenerator.strings; - } else { - // ### collect from available QV4::CompiledData::QmlUnit - } - for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = typeReferences.constBegin(), end = typeReferences.constEnd(); + for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd(); unresolvedRef != end; ++unresolvedRef) { TypeReference ref; // resolved reference @@ -2355,15 +2406,15 @@ void QQmlTypeData::resolveTypes() QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - const QString name = names.at(unresolvedRef.key()); - bool typeFound = m_imports.resolveType(name, &ref.type, + const QString name = stringAt(unresolvedRef.key()); + bool typeFound = m_importCache.resolveType(name, &ref.type, &majorVersion, &minorVersion, &typeNamespace, &errors); if (!typeNamespace && !typeFound && !m_implicitImportLoaded) { // Lazy loading of implicit import if (loadImplicitImport()) { // Try again to find the type errors.clear(); - typeFound = m_imports.resolveType(name, &ref.type, + typeFound = m_importCache.resolveType(name, &ref.type, &majorVersion, &minorVersion, &typeNamespace, &errors); } else { return; //loadImplicitImport() hit an error, and called setError already @@ -2385,7 +2436,7 @@ void QQmlTypeData::resolveTypes() // Description should come from error provided by addImport() function. error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database")); } - error.setUrl(m_imports.baseUrl()); + error.setUrl(m_importCache.baseUrl()); error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description())); } @@ -2413,19 +2464,19 @@ void QQmlTypeData::resolveTypes() } } -bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref) +bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref) { QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; - bool typeFound = m_imports.resolveType(parserRef->name, &ref.type, + bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, &typeNamespace, &errors); if (!typeNamespace && !typeFound && !m_implicitImportLoaded) { // Lazy loading of implicit import if (loadImplicitImport()) { // Try again to find the type errors.clear(); - typeFound = m_imports.resolveType(parserRef->name, &ref.type, + typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, &typeNamespace, &errors); } else { return false; //loadImplicitImport() hit an error, and called setError already @@ -2438,7 +2489,7 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int & // - type with unknown namespace (UnknownNamespace.SomeType {}) QQmlError error; if (typeNamespace) { - error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name)); + error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName)); } else { if (errors.size()) { error = errors.takeFirst(); @@ -2447,8 +2498,8 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int & // Description should come from error provided by addImport() function. error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database")); } - error.setUrl(m_imports.baseUrl()); - error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description())); + error.setUrl(m_importCache.baseUrl()); + error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description())); } errors.prepend(error); @@ -2459,7 +2510,7 @@ bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int & return true; } -void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/) +void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/) { ScriptReference ref; ref.script = blob; @@ -2471,7 +2522,6 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Locati QQmlScriptData::QQmlScriptData() : importCache(0) - , pragmas(QQmlScript::Object::ScriptBlock::None) , m_loaded(false) , m_precompiledScript(0) , m_program(0) @@ -2517,7 +2567,7 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare QV4::ExecutionEngine *v4 = QV8Engine::getV4(parentCtxt->engine); QV4::Scope scope(v4); - bool shared = pragmas & QQmlScript::Object::ScriptBlock::Shared; + bool shared = m_precompiledScript->data->flags & QV4::CompiledData::Unit::IsSharedLibrary; QQmlContextData *effectiveCtxt = parentCtxt; if (shared) @@ -2621,11 +2671,6 @@ QQmlScriptBlob::~QQmlScriptBlob() } } -QQmlScript::Object::ScriptBlock::Pragmas QQmlScriptBlob::pragmas() const -{ - return m_metadata.pragmas; -} - QQmlScriptData *QQmlScriptBlob::scriptData() const { return m_scriptData; @@ -2633,36 +2678,49 @@ QQmlScriptData *QQmlScriptBlob::scriptData() const void QQmlScriptBlob::dataReceived(const Data &data) { - m_source = QString::fromUtf8(data.data(), data.size()); + QString source = QString::fromUtf8(data.data(), data.size()); - m_scriptData = new QQmlScriptData(); - m_scriptData->url = finalUrl(); - m_scriptData->urlString = finalUrlString(); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); + QmlIR::Document irUnit(v4->debugger != 0); + QQmlJS::DiagnosticMessage metaDataError; + irUnit.extractScriptMetaData(source, &metaDataError); + if (!metaDataError.message.isEmpty()) { + QQmlError e; + e.setUrl(finalUrl()); + e.setLine(metaDataError.loc.startLine); + e.setColumn(metaDataError.loc.startColumn); + e.setDescription(metaDataError.message); + setError(e); + return; + } - QQmlError metaDataError; - m_metadata = QQmlScript::Parser::extractMetaData(m_source, &metaDataError); - if (metaDataError.isValid()) { - metaDataError.setUrl(finalUrl()); - setError(metaDataError); + QList<QQmlError> errors; + QV4::CompiledData::CompilationUnit *unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors); + if (unit) + unit->ref(); + source.clear(); + if (!errors.isEmpty()) { + if (unit) + unit->deref(); + setError(errors); return; } + irUnit.javaScriptCompilationUnit = unit; - m_imports.setBaseUrl(finalUrl(), finalUrlString()); + QmlIR::QmlUnitGenerator qmlGenerator; + QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(irUnit); + Q_ASSERT(!unit->data); + Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header); + // The js unit owns the data and will free the qml unit. + unit->data = &qmlUnit->header; - QList<QQmlError> errors; + initializeFromCompilationUnit(unit); + unit->deref(); +} - foreach (const QQmlScript::Import &import, m_metadata.imports) { - if (!addImport(import, &errors)) { - Q_ASSERT(errors.size()); - QQmlError error(errors.takeFirst()); - error.setUrl(m_imports.baseUrl()); - error.setLine(import.location.start.line); - error.setColumn(import.location.start.column); - errors.prepend(error); // put it back on the list after filling out information. - setError(errors); - return; - } - } +void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) +{ + initializeFromCompilationUnit(unit->createCompilationUnit()); } void QQmlScriptBlob::done() @@ -2704,23 +2762,15 @@ void QQmlScriptBlob::done() m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace); } - m_imports.populateCache(m_scriptData->importCache); - - m_scriptData->pragmas = m_metadata.pragmas; + m_importCache.populateCache(m_scriptData->importCache); +} - QList<QQmlError> errors; - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); - m_scriptData->m_precompiledScript = QV4::Script::precompile(v4, m_scriptData->url, m_source, &errors); - if (m_scriptData->m_precompiledScript) - m_scriptData->m_precompiledScript->ref(); - m_source.clear(); - if (!errors.isEmpty()) { - setError(errors); - return; - } +QString QQmlScriptBlob::stringAt(int index) const +{ + return m_scriptData->m_precompiledScript->data->stringAt(index); } -void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace) +void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) { ScriptReference ref; ref.script = blob; @@ -2731,6 +2781,37 @@ void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Loca m_scripts << ref; } +void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit) +{ + Q_ASSERT(!m_scriptData); + m_scriptData = new QQmlScriptData(); + 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()); + + Q_ASSERT(m_scriptData->m_precompiledScript->data->flags & QV4::CompiledData::Unit::IsQml); + const QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<const QV4::CompiledData::QmlUnit*>(m_scriptData->m_precompiledScript->data); + + QList<QQmlError> errors; + for (quint32 i = 0; i < qmlUnit->nImports; ++i) { + const QV4::CompiledData::Import *import = qmlUnit->importAt(i); + if (!addImport(import, &errors)) { + Q_ASSERT(errors.size()); + QQmlError error(errors.takeFirst()); + error.setUrl(m_importCache.baseUrl()); + error.setLine(import->location.line); + error.setColumn(import->location.column); + errors.prepend(error); // put it back on the list after filling out information. + setError(errors); + return; + } + } +} + QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader) : QQmlTypeLoader::Blob(url, QmldirFile, loader), m_import(0), m_priority(0) { @@ -2741,12 +2822,12 @@ const QString &QQmlQmldirData::content() const return m_content; } -const QQmlScript::Import *QQmlQmldirData::import() const +const QV4::CompiledData::Import *QQmlQmldirData::import() const { return m_import; } -void QQmlQmldirData::setImport(const QQmlScript::Import *import) +void QQmlQmldirData::setImport(const QV4::CompiledData::Import *import) { m_import = import; } @@ -2766,6 +2847,11 @@ void QQmlQmldirData::dataReceived(const Data &data) m_content = QString::fromUtf8(data.data(), data.size()); } +void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) +{ + Q_UNIMPLEMENTED(); +} + QT_END_NAMESPACE #include "qqmltypeloader.moc" diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 9cd28a03ce..b09ac15861 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -62,12 +62,12 @@ #include <QtQml/qqmlabstracturlinterceptor.h> #include <private/qhashedstring_p.h> -#include <private/qqmlscript_p.h> #include <private/qqmlimport_p.h> #include <private/qqmlcleanup_p.h> #include <private/qqmldirparser_p.h> #include <private/qqmlbundle_p.h> #include <private/qflagpointer_p.h> +#include <private/qqmlirbuilder_p.h> #include <private/qv4value_inl_p.h> #include <private/qv4script_p.h> @@ -84,8 +84,8 @@ class QQmlTypeData; class QQmlDataLoader; class QQmlExtensionInterface; -namespace QtQml { -struct ParsedQML; +namespace QmlIR { +struct Document; } class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount @@ -155,6 +155,7 @@ protected: // Callbacks made in load thread virtual void dataReceived(const Data &) = 0; + virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0; virtual void done(); virtual void networkError(QNetworkReply::NetworkError); virtual void dependencyError(QQmlDataBlob *); @@ -228,6 +229,7 @@ public: void load(QQmlDataBlob *, Mode = PreferSynchronous); void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous); + void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); QQmlEngine *engine() const; void initializeEngine(QQmlExtensionInterface *, const char *); @@ -242,6 +244,7 @@ private: void loadThread(QQmlDataBlob *); void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &); + void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); void networkReplyFinished(QNetworkReply *); void networkReplyProgress(QNetworkReply *, qint64, qint64); @@ -250,6 +253,7 @@ private: void setData(QQmlDataBlob *, const QByteArray &); void setData(QQmlDataBlob *, QQmlFile *); void setData(QQmlDataBlob *, const QQmlDataBlob::Data &); + void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); QQmlEngine *m_engine; QQmlDataLoaderThread *m_thread; @@ -275,28 +279,30 @@ public: ~Blob(); QQmlTypeLoader *typeLoader() const { return m_typeLoader; } - const QQmlImports &imports() const { return m_imports; } + const QQmlImports &imports() const { return m_importCache; } protected: - bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors); - bool addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors); + bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors); + bool addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors); - bool fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors); - bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors); + bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors); + bool updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors); private: virtual bool qmldirDataAvailable(QQmlQmldirData *, QList<QQmlError> *); - virtual void scriptImported(QQmlScriptBlob *, const QQmlScript::Location &, const QString &, const QString &) {} + virtual void scriptImported(QQmlScriptBlob *, const QV4::CompiledData::Location &, const QString &, const QString &) {} virtual void dependencyError(QQmlDataBlob *); virtual void dependencyComplete(QQmlDataBlob *); protected: + virtual QString stringAt(int) const { return QString(); } + QQmlTypeLoader *m_typeLoader; - QQmlImports m_imports; + QQmlImports m_importCache; bool m_isSingleton; - QHash<const QQmlScript::Import *, int> m_unresolvedImports; + QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports; QList<QQmlQmldirData *> m_qmldirs; }; @@ -398,7 +404,7 @@ public: { TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {} - QQmlScript::Location location; + QV4::CompiledData::Location location; QQmlType *type; int majorVersion; int minorVersion; @@ -411,7 +417,7 @@ public: { ScriptReference() : script(0) {} - QQmlScript::Location location; + QV4::CompiledData::Location location; QString qualifier; QQmlScriptBlob *script; }; @@ -445,19 +451,21 @@ protected: virtual void done(); virtual void completed(); virtual void dataReceived(const Data &); + virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit); virtual void allDependenciesDone(); virtual void downloadProgressChanged(qreal); + virtual QString stringAt(int index) const; + private: + void continueLoadFromIR(); void resolveTypes(); void compile(); - bool resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref); + bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref); - virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace); + virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace); - QScopedPointer<QtQml::ParsedQML> parsedQML; - QList<QQmlScript::Import> m_newImports; - QList<QQmlScript::Pragma> m_newPragmas; + QScopedPointer<QmlIR::Document> m_document; QList<ScriptReference> m_scripts; @@ -472,7 +480,7 @@ private: QList<TypeDataCallback *> m_callbacks; - QQmlScript::Import *m_implicitImport; + QV4::CompiledData::Import *m_implicitImport; bool m_implicitImportLoaded; bool loadImplicitImport(); }; @@ -498,7 +506,6 @@ public: QString urlString; QQmlTypeNameCache *importCache; QList<QQmlScriptBlob *> scripts; - QQmlScript::Object::ScriptBlock::Pragmas pragmas; QV4::PersistentValue scriptValueForContext(QQmlContextData *parentCtxt); @@ -506,7 +513,6 @@ protected: virtual void clear(); // From QQmlCleanup private: - friend class QQmlVME; friend class QQmlScriptBlob; void initialize(QQmlEngine *); @@ -531,25 +537,24 @@ public: { ScriptReference() : script(0) {} - QQmlScript::Location location; + QV4::CompiledData::Location location; QString qualifier; QString nameSpace; QQmlScriptBlob *script; }; - QQmlScript::Object::ScriptBlock::Pragmas pragmas() const; - QQmlScriptData *scriptData() const; protected: virtual void dataReceived(const Data &); + virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit); virtual void done(); -private: - virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace); + virtual QString stringAt(int index) const; - QString m_source; - QQmlScript::Parser::JavaScriptMetaData m_metadata; +private: + virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace); + void initializeFromCompilationUnit(QV4::CompiledData::CompilationUnit *unit); QList<ScriptReference> m_scripts; QQmlScriptData *m_scriptData; @@ -565,18 +570,19 @@ private: public: const QString &content() const; - const QQmlScript::Import *import() const; - void setImport(const QQmlScript::Import *); + const QV4::CompiledData::Import *import() const; + void setImport(const QV4::CompiledData::Import *); int priority() const; void setPriority(int); protected: virtual void dataReceived(const Data &); + virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*); private: QString m_content; - const QQmlScript::Import *m_import; + const QV4::CompiledData::Import *m_import; int m_priority; }; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index e599c37c0c..1ff95a245d 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -615,7 +615,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, QQmlVMEMetaData::MethodData *data = metaData->methodData() + index; QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex]; - o = QV4::FunctionObject::creatScriptFunction(qmlBindingContext, runtimeFunction); + o = QV4::FunctionObject::createScriptFunction(qmlBindingContext, runtimeFunction); v8methods[index] = o; } } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index e2cdac16c0..d89dc92b68 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -905,8 +905,11 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty { QV4::ExecutionEngine *v4 = m->engine(); NamedNodeMap *r = m->as<NamedNodeMap>(); - if (!r) + if (!r) { + if (hasProperty) + *hasProperty = false; return v4->currentContext()->throwTypeError(); + } QV8Engine *engine = v4->v8Engine; @@ -960,8 +963,11 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) { QV4::ExecutionEngine *v4 = m->engine(); NodeList *r = m->as<NodeList>(); - if (!r) + if (!r) { + if (hasProperty) + *hasProperty = false; return v4->currentContext()->throwTypeError(); + } QV8Engine *engine = v4->v8Engine; @@ -1388,7 +1394,8 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::ContentNotFoundError || error == QNetworkReply::AuthenticationRequiredError || error == QNetworkReply::ContentReSendError || - error == QNetworkReply::UnknownContentError) { + error == QNetworkReply::UnknownContentError || + error == QNetworkReply::ProtocolInvalidOperationError) { m_state = Loading; dispatchCallback(me); } else { @@ -1650,6 +1657,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>(); if (c->proto) c->proto->mark(e); + FunctionObject::markObjects(that, e); } static ReturnedValue construct(Managed *that, QV4::CallData *) { diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 61b466a5db..8305649177 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -601,7 +601,11 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap) for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) { s = m_v4Engine->newIdentifier(it.key()); v = variantToJS(it.value()); - o->insertMember(s, v); + uint idx = s->asArrayIndex(); + if (idx < UINT_MAX) + o->arraySet(idx, v); + else + o->insertMember(s, v); } return o.asReturnedValue(); } |