From 627226520a2bbb977ce32a21bdffd2004cb28796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Fri, 12 Oct 2018 16:56:14 +0200 Subject: Expose let/const variables from imported JS scripts This patch allows QML to access let/const variables defined in JS files. Detailed changes: - The recently added ContextType::ScriptImportedByQML is changed to avoid creating Push/PopScriptContext instructions, similar to ContextType::ESModule. - QV4::Module is changed to also work with CompilationUnits which are not ESModules. In this case QV4::Module will behave as if all lexically scoped variables were exported. - CompilationUnit is changed to support instantiating and evaluating QV4::Modules for non-ESModules as well. - QQmlTypeLoader is changed to always create QV4::Modules for evaluating scripts. For the non-ESModule case, the QV4::Module is evaluated inside a QV4::QmlContext, as before. - A pointer to the QV4::Module is added to QV4::QQmlContextWrapper, and used in virtualGet to access the let/const variables in the CallContext. Access is read-only. Fixes: QTBUG-69408 Change-Id: I6f299363fdf5e1c5a4a0f1d9e655b4dc5112dd00 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypeloader.cpp | 86 +++++++++++++++--------------------------- src/qml/qml/qqmltypeloader_p.h | 3 -- 2 files changed, 31 insertions(+), 58 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 89b023c164..7480475ca7 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2881,30 +2881,9 @@ void QQmlTypeData::scriptImported(const QQmlRefPointer &blob, co QQmlScriptData::QQmlScriptData() : typeNameCache(nullptr) , m_loaded(false) - , m_program(nullptr) { } -QQmlScriptData::~QQmlScriptData() -{ - delete m_program; -} - -void QQmlScriptData::initialize(QQmlEngine *engine) -{ - Q_ASSERT(!m_program); - Q_ASSERT(engine); - Q_ASSERT(!hasEngine()); - - QV4::ExecutionEngine *v4 = engine->handle(); - - m_program = new QV4::Script(v4, nullptr, m_precompiledScript); - - addToEngine(engine); - - addref(); -} - QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData) { Q_ASSERT(parentQmlContextData && parentQmlContextData->engine); @@ -2954,57 +2933,54 @@ QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *paren return qmlContextData; } -QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentCtxt) +QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData) { if (m_loaded) return m_value.value(); - Q_ASSERT(parentCtxt && parentCtxt->engine); - QV4::ExecutionEngine *v4 = parentCtxt->engine->handle(); - - if (m_precompiledScript->isESModule()) { - m_loaded = true; - - m_value.set(v4, m_precompiledScript->instantiate(v4)); - if (!m_value.isNullOrUndefined()) - m_precompiledScript->evaluate(); + Q_ASSERT(parentQmlContextData && parentQmlContextData->engine); + QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle(); + QV4::Scope scope(v4); - return m_value.value(); + if (!hasEngine()) { + addToEngine(parentQmlContextData->engine); + addref(); } - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine); - QV4::Scope scope(v4); - - // Create the script context if required - QQmlContextDataRef ctxt(qmlContextDataForContext(parentCtxt)); + QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData); + QV4::Scoped qmlExecutionContext(scope); + if (qmlContextData) + qmlExecutionContext = + QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr); - if (!hasEngine()) - initialize(parentCtxt->engine); + QV4::Scoped module(scope, m_precompiledScript->instantiate(v4)); + if (module) { + if (qmlContextData) { + module->d()->scope->outer.set(v4, qmlExecutionContext->d()); + qmlExecutionContext->d()->qml()->module.set(v4, module->d()); + } - if (!m_program) { - if (m_precompiledScript->isSharedLibrary()) - m_loaded = true; - return QV4::Encode::undefined(); + module->evaluate(); } - QV4::Scoped qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, nullptr)); - - m_program->qmlContext.set(scope.engine, qmlContext); - m_program->run(); - m_program->qmlContext.clear(); - if (scope.engine->hasException) { - QQmlError error = scope.engine->catchExceptionAsQmlError(); + if (v4->hasException) { + QQmlError error = v4->catchExceptionAsQmlError(); if (error.isValid()) - ep->warning(error); + QQmlEnginePrivate::get(v4)->warning(error); } - QV4::ScopedValue retval(scope, qmlContext->d()->qml()); - if (m_precompiledScript->isSharedLibrary()) { - m_value.set(scope.engine, retval); + QV4::ScopedValue value(scope); + if (qmlContextData) + value = qmlExecutionContext->d()->qml(); + else if (module) + value = module->d(); + + if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) { m_loaded = true; + m_value.set(v4, value); } - return retval->asReturnedValue(); + return value->asReturnedValue(); } void QQmlScriptData::clear() diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 29c91346de..5bb4e9d490 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -534,8 +534,6 @@ private: QQmlScriptData(); public: - ~QQmlScriptData() override; - QUrl url; QString urlString; QQmlTypeNameCache *typeNameCache; @@ -556,7 +554,6 @@ private: bool m_loaded; QQmlRefPointer m_precompiledScript; - QV4::Script *m_program; QV4::PersistentValue m_value; }; -- cgit v1.2.3