diff options
author | Jüri Valdmann <[email protected]> | 2018-10-12 16:56:14 +0200 |
---|---|---|
committer | Jani Heikkinen <[email protected]> | 2018-11-02 16:44:11 +0000 |
commit | 627226520a2bbb977ce32a21bdffd2004cb28796 (patch) | |
tree | e3989c73887505a179e875baf2984be10fcbdda8 /src/qml/jsruntime/qv4module.cpp | |
parent | f20839aed0f2e4fe9134a239adda4853d7bd204a (diff) |
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 <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4module.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4module.cpp | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp index 19a036374f..237ada8321 100644 --- a/src/qml/jsruntime/qv4module.cpp +++ b/src/qml/jsruntime/qv4module.cpp @@ -46,6 +46,8 @@ #include <private/qv4symbol_p.h> #include <private/qv4identifiertable_p.h> +#include <QScopeGuard> + using namespace QV4; DEFINE_OBJECT_VTABLE(Module); @@ -98,20 +100,60 @@ void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit * This->setPrototypeUnchecked(nullptr); } +void Module::evaluate() +{ + if (d()->evaluated) + return; + d()->evaluated = true; + + CompiledData::CompilationUnit *unit = d()->unit; + + unit->evaluateModuleRequests(); + + ExecutionEngine *v4 = engine(); + Function *moduleFunction = unit->runtimeFunctions[unit->data->indexOfRootFunction]; + CppStackFrame frame; + frame.init(v4, moduleFunction, nullptr, 0); + frame.setupJSFrame(v4->jsStackTop, Value::undefinedValue(), d()->scope, + Value::undefinedValue(), Value::undefinedValue()); + + frame.push(); + v4->jsStackTop += frame.requiredJSStackFrameSize(); + auto frameCleanup = qScopeGuard([&frame]() { + frame.pop(); + }); + Moth::VME::exec(&frame, v4); +} + +const Value *Module::resolveExport(PropertyKey id) const +{ + if (d()->unit->isESModule()) { + if (!id.isString()) + return nullptr; + Scope scope(engine()); + ScopedString name(scope, id.asStringOrSymbol()); + return d()->unit->resolveExport(name); + } else { + InternalClassEntry entry = d()->scope->internalClass->find(id); + if (entry.isValid()) + return &d()->scope->locals[entry.index]; + return nullptr; + } +} + ReturnedValue Module::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { if (id.isSymbol()) return Object::virtualGet(m, id, receiver, hasProperty); const Module *module = static_cast<const Module *>(m); - Scope scope(m->engine()); - ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); - const Value *v = module->d()->unit->resolveExport(expectedName); + const Value *v = module->resolveExport(id); if (hasProperty) *hasProperty = v != nullptr; if (!v) return Encode::undefined(); if (v->isEmpty()) { + Scope scope(m->engine()); ScopedValue propName(scope, id.toStringOrSymbol(scope.engine)); return scope.engine->throwReferenceError(propName); } @@ -124,9 +166,7 @@ PropertyAttributes Module::virtualGetOwnProperty(const Managed *m, PropertyKey i return Object::virtualGetOwnProperty(m, id, p); const Module *module = static_cast<const Module *>(m); - Scope scope(m->engine()); - ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); - const Value *v = module->d()->unit->resolveExport(expectedName); + const Value *v = module->resolveExport(id); if (!v) { if (p) p->value = Encode::undefined(); @@ -135,6 +175,7 @@ PropertyAttributes Module::virtualGetOwnProperty(const Managed *m, PropertyKey i if (p) p->value = v->isEmpty() ? Encode::undefined() : v->asReturnedValue(); if (v->isEmpty()) { + Scope scope(m->engine()); ScopedValue propName(scope, id.toStringOrSymbol(scope.engine)); scope.engine->throwReferenceError(propName); } @@ -147,9 +188,7 @@ bool Module::virtualHasProperty(const Managed *m, PropertyKey id) return Object::virtualHasProperty(m, id); const Module *module = static_cast<const Module *>(m); - Scope scope(m->engine()); - ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); - const Value *v = module->d()->unit->resolveExport(expectedName); + const Value *v = module->resolveExport(id); return v != nullptr; } @@ -173,11 +212,7 @@ bool Module::virtualDeleteProperty(Managed *m, PropertyKey id) if (id.isSymbol()) return Object::virtualDeleteProperty(m, id); const Module *module = static_cast<const Module *>(m); - Scope scope(m->engine()); - ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); - if (!expectedName) - return true; - const Value *v = module->d()->unit->resolveExport(expectedName); + const Value *v = module->resolveExport(id); if (v) return false; return true; @@ -202,7 +237,7 @@ PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, Propert Scope scope(module->engine()); ScopedString exportName(scope, scope.engine->newString(exportedNames.at(exportIndex))); exportIndex++; - const Value *v = module->d()->unit->resolveExport(exportName); + const Value *v = module->resolveExport(exportName->toPropertyKey()); if (pd) { if (v->isEmpty()) scope.engine->throwReferenceError(exportName); @@ -218,7 +253,17 @@ OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *t { const Module *module = static_cast<const Module *>(o); *target = *o; - return new ModuleNamespaceIterator(module->d()->unit->exportedNames()); + + QStringList names; + if (module->d()->unit->isESModule()) { + names = module->d()->unit->exportedNames(); + } else { + Heap::InternalClass *scopeClass = module->d()->scope->internalClass; + for (uint i = 0; i < scopeClass->size; ++i) + names << scopeClass->keyAt(i); + } + + return new ModuleNamespaceIterator(names); } Heap::Object *Module::virtualGetPrototypeOf(const Managed *) |