diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/jsruntime.pri | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 99 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4module.cpp | 69 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4module_p.h | 82 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 |
6 files changed, 273 insertions, 2 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ec5803b2df..c42c2d48c8 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -55,7 +55,8 @@ SOURCES += \ $$PWD/qv4vme_moth.cpp \ $$PWD/qv4mapobject.cpp \ $$PWD/qv4mapiterator.cpp \ - $$PWD/qv4estable.cpp + $$PWD/qv4estable.cpp \ + $$PWD/qv4module.cpp qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp @@ -123,7 +124,8 @@ HEADERS += \ $$PWD/qv4mapobject_p.h \ $$PWD/qv4mapiterator_p.h \ $$PWD/qv4estable_p.h \ - $$PWD/qv4vtable_p.h + $$PWD/qv4vtable_p.h \ + $$PWD/qv4module_p.h qtConfig(qml-sequence-object) { HEADERS += \ diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index fcc2feced4..69b23484a8 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -75,6 +75,10 @@ #include "qv4reflect_p.h" #include "qv4proxy_p.h" #include "qv4stackframe_p.h" +#include <private/qqmljsengine_p.h> +#include <private/qqmljslexer_p.h> +#include <private/qqmljsparser_p.h> +#include <private/qqmljsast_p.h> #if QT_CONFIG(qml_sequence_object) #include "qv4sequenceobject_p.h" @@ -92,12 +96,16 @@ #include <private/qqmlvaluetype_p.h> #include <private/qqmllistwrapper_p.h> #include <private/qqmllist_p.h> +#include <private/qqmltypeloader_p.h> #if QT_CONFIG(qml_locale) #include <private/qqmllocale_p.h> #endif +#include <qqmlfile.h> #include <QtCore/QTextStream> #include <QDateTime> +#include <QDir> +#include <QFileInfo> #if USE(PTHREADS) # include <pthread.h> @@ -593,6 +601,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) ExecutionEngine::~ExecutionEngine() { + modules.clear(); delete m_multiplyWrappedQObjects; m_multiplyWrappedQObjects = nullptr; delete identifierTable; @@ -1621,6 +1630,96 @@ ReturnedValue ExecutionEngine::global() return globalObject->asReturnedValue(); } +QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(const QUrl &url) +{ + QFile f(QQmlFile::urlToLocalFileOrQrc(url)); + if (!f.open(QIODevice::ReadOnly)) + return nullptr; + + const QString sourceCode = QString::fromUtf8(f.readAll()); + f.close(); + + return compileModule(url, sourceCode); +} + + +QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode) +{ + QList<QQmlJS::DiagnosticMessage> diagnostics; + auto unit = compileModule(/*debugMode*/debugger() != nullptr, url, sourceCode, &diagnostics); + for (const QQmlJS::DiagnosticMessage &m : diagnostics) { + if (m.isError()) { + throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); + return nullptr; + } else { + qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn + << ": warning: " << m.message; + } + } + return unit; +} + +QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList<QQmlJS::DiagnosticMessage> *diagnostics) +{ + QQmlJS::Engine ee; + QQmlJS::Lexer lexer(&ee); + lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false); + QQmlJS::Parser parser(&ee); + + const bool parsed = parser.parseModule(); + + if (diagnostics) + *diagnostics = parser.diagnosticMessages(); + + if (!parsed) + return nullptr; + + QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode()); + if (!moduleNode) { + // if parsing was successful, and we have no module, then + // the file was empty. + if (diagnostics) + diagnostics->clear(); + return nullptr; + } + + using namespace QV4::Compiler; + Compiler::Module compilerModule(debugMode); + JSUnitGenerator jsGenerator(&compilerModule); + Codegen cg(&jsGenerator, /*strictMode*/true); + cg.generateFromModule(url.fileName(), url.toString(), sourceCode, moduleNode, &compilerModule); + auto errors = cg.errors(); + if (diagnostics) + *diagnostics << errors; + + if (!errors.isEmpty()) + return nullptr; + + return cg.generateCompilationUnit(); +} + +void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit) +{ + modules.insert(moduleUnit->finalUrl(), moduleUnit); +} + +QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, CompiledData::CompilationUnit *referrer) +{ + QUrl url = QQmlTypeLoader::normalize(_url); + if (referrer) + url = referrer->finalUrl().resolved(url); + + auto existingModule = modules.find(url); + if (existingModule != modules.end()) + return *existingModule; + + auto newModule = compileModule(url); + if (newModule) + modules.insert(url, newModule); + + return newModule; +} + // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index e1ea89c699..e605be9901 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -86,6 +86,10 @@ namespace CompiledData { struct CompilationUnit; } +namespace Heap { +struct Module; +}; + struct Function; @@ -556,6 +560,17 @@ public: QV4::ReturnedValue global(); double localTZA = 0.0; // local timezone, initialized at startup + +#ifndef V4_BOOTSTRAP + QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url); + QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url, const QString &sourceCode); + static QQmlRefPointer<CompiledData::CompilationUnit> compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList<QQmlJS::DiagnosticMessage> *diagnostics); + + QHash<QUrl, QQmlRefPointer<CompiledData::CompilationUnit>> modules; + void injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit); + QQmlRefPointer<CompiledData::CompilationUnit> loadModule(const QUrl &_url, CompiledData::CompilationUnit *referrer = nullptr); +#endif + private: #if QT_CONFIG(qml_debug) QScopedPointer<QV4::Debugging::Debugger> m_debugger; diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp new file mode 100644 index 0000000000..ed7df459b6 --- /dev/null +++ b/src/qml/jsruntime/qv4module.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qv4module_p.h" + +#include <private/qv4mm_p.h> +#include <private/qv4vme_moth_p.h> +#include <private/qv4context_p.h> + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(Module); + +void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit) +{ + Object::init(); + + // This is a back pointer and there is no need to call addref() on the unit, because the unit + // owns this object instead. + unit = moduleUnit; + + Function *moduleFunction = unit->runtimeFunctions[unit->unitData()->indexOfRootFunction]; + + const uint locals = moduleFunction->compiledFunction->nLocals; + const size_t requiredMemory = sizeof(QV4::CallContext::Data) - sizeof(Value) + sizeof(Value) * locals; + scope.set(engine, engine->memoryManager->allocManaged<QV4::CallContext>(requiredMemory, moduleFunction->internalClass)); + scope->init(); + scope->outer.set(engine, engine->rootContext()->d()); + scope->locals.size = locals; + scope->locals.alloc = locals; + scope->nArgs = 0; +} diff --git a/src/qml/jsruntime/qv4module_p.h b/src/qml/jsruntime/qv4module_p.h new file mode 100644 index 0000000000..1958258ef0 --- /dev/null +++ b/src/qml/jsruntime/qv4module_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4MODULE +#define QV4MODULE + +// +// 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 "qv4object_p.h" +#include "qv4context_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +namespace Heap { + +#define ModuleMembers(class, Member) \ + Member(class, NoMark, CompiledData::CompilationUnit *, unit) \ + Member(class, Pointer, CallContext *, scope) + +DECLARE_EXPORTED_HEAP_OBJECT(Module, Object) { + DECLARE_MARKOBJECTS(Module) + + void init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit); +}; + +} + +struct Q_QML_EXPORT Module : public Object { + V4_OBJECT2(Module, Object) +}; + +} + +QT_END_NAMESPACE + +#endif // QV4MODULE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 53e5632eff..575cad70e4 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -503,6 +503,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, STACK_VALUE(destReg) = STACK_VALUE(srcReg); MOTH_END_INSTR(MoveReg) + MOTH_BEGIN_INSTR(LoadImport) + acc = function->compilationUnit->imports[index]->asReturnedValue(); + MOTH_END_INSTR(LoadImport) + MOTH_BEGIN_INSTR(LoadLocal) auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext); |